summaryrefslogtreecommitdiff
path: root/vcl/aqua/source/gdi/salnativewidgets.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/aqua/source/gdi/salnativewidgets.cxx')
-rw-r--r--vcl/aqua/source/gdi/salnativewidgets.cxx1529
1 files changed, 1529 insertions, 0 deletions
diff --git a/vcl/aqua/source/gdi/salnativewidgets.cxx b/vcl/aqua/source/gdi/salnativewidgets.cxx
new file mode 100644
index 000000000000..9ce2b8a5a518
--- /dev/null
+++ b/vcl/aqua/source/gdi/salnativewidgets.cxx
@@ -0,0 +1,1529 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#include "salconst.h"
+#include "salgdi.h"
+#include "salnativewidgets.h"
+#include "saldata.hxx"
+#include "salframe.h"
+
+#include "vcl/salnativewidgets.hxx"
+#include "vcl/decoview.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/timer.hxx"
+
+#include "premac.h"
+#include <Carbon/Carbon.h>
+#include "postmac.h"
+
+class AquaBlinker : public Timer
+{
+ AquaSalFrame* mpFrame;
+ Rectangle maInvalidateRect;
+
+ AquaBlinker( AquaSalFrame* pFrame, const Rectangle& rRect )
+ : mpFrame( pFrame ), maInvalidateRect( rRect )
+ {
+ mpFrame->maBlinkers.push_back( this );
+ }
+
+ public:
+
+ static void Blink( AquaSalFrame*, const Rectangle&, int nTimeout = 80 );
+
+ virtual void Timeout()
+ {
+ Stop();
+ if( AquaSalFrame::isAlive( mpFrame ) && mpFrame->mbShown )
+ {
+ mpFrame->maBlinkers.remove( this );
+ mpFrame->SendPaintEvent( &maInvalidateRect );
+ }
+ delete this;
+ }
+};
+
+void AquaBlinker::Blink( AquaSalFrame* pFrame, const Rectangle& rRect, int nTimeout )
+{
+ // prevent repeated paints from triggering themselves all the time
+ for( std::list< AquaBlinker* >::const_iterator it = pFrame->maBlinkers.begin();
+ it != pFrame->maBlinkers.end(); ++it )
+ {
+ if( (*it)->maInvalidateRect == rRect )
+ return;
+ }
+ AquaBlinker* pNew = new AquaBlinker( pFrame, rRect );
+ pNew->SetTimeout( nTimeout );
+ pNew->Start();
+}
+
+ControlPart ImplgetCounterPart( ControlPart nPart )
+{
+ ControlPart nCounterPart = 0;
+ switch (nPart)
+ {
+ case PART_BUTTON_UP:
+ nCounterPart = PART_BUTTON_DOWN;
+ break;
+ case PART_BUTTON_DOWN:
+ nCounterPart = PART_BUTTON_UP;
+ break;
+ case PART_BUTTON_LEFT:
+ nCounterPart = PART_BUTTON_RIGHT;
+ break;
+ case PART_BUTTON_RIGHT:
+ nCounterPart = PART_BUTTON_LEFT;
+ break;
+ }
+ return nCounterPart;
+}
+
+
+// Helper returns an HIRect
+
+static HIRect ImplGetHIRectFromRectangle(Rectangle aRect)
+{
+ HIRect aHIRect;
+ aHIRect.origin.x = static_cast<float>(aRect.Left());
+ aHIRect.origin.y = static_cast<float>(aRect.Top());
+ aHIRect.size.width = static_cast<float>(aRect.GetWidth());
+ aHIRect.size.height = static_cast<float>(aRect.GetHeight());
+ return aHIRect;
+}
+
+static ThemeButtonValue ImplGetButtonValue( ButtonValue aButtonValue )
+{
+ switch( aButtonValue )
+ {
+ case BUTTONVALUE_ON:
+ return kThemeButtonOn;
+ break;
+
+ case BUTTONVALUE_OFF:
+ return kThemeButtonOff;
+ break;
+
+ case BUTTONVALUE_MIXED:
+ case BUTTONVALUE_DONTKNOW:
+ default:
+ return kThemeButtonMixed;
+ break;
+ }
+}
+
+static bool AquaGetScrollRect( /* TODO: int nScreen, */ ControlPart nPart,
+ const Rectangle& rControlRect, Rectangle& rResultRect )
+{
+ bool bRetVal = true;
+ rResultRect = rControlRect;
+
+ switch( nPart )
+ {
+ case PART_BUTTON_UP:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Top() = rControlRect.Bottom() - 2*BUTTON_HEIGHT;
+ rResultRect.Bottom() = rResultRect.Top() + BUTTON_HEIGHT;
+ break;
+
+ case PART_BUTTON_DOWN:
+ rResultRect.Top() = rControlRect.Bottom() - BUTTON_HEIGHT;
+ break;
+
+ case PART_BUTTON_LEFT:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Left() = rControlRect.Right() - 2*BUTTON_WIDTH;
+ rResultRect.Right() = rResultRect.Left() + BUTTON_WIDTH;
+ break;
+
+ case PART_BUTTON_RIGHT:
+ rResultRect.Left() = rControlRect.Right() - BUTTON_WIDTH;
+ break;
+
+ case PART_TRACK_HORZ_AREA:
+ rResultRect.Right() -= BUTTON_WIDTH + 1;
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Right() -= BUTTON_WIDTH;
+ else
+ rResultRect.Left() += BUTTON_WIDTH + 1;
+ break;
+
+ case PART_TRACK_VERT_AREA:
+ rResultRect.Bottom() -= BUTTON_HEIGHT + 1;
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Bottom() -= BUTTON_HEIGHT;
+ else
+ rResultRect.Top() += BUTTON_HEIGHT + 1;
+ break;
+ case PART_THUMB_HORZ:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ {
+ rResultRect.Left() += 8;
+ rResultRect.Right() += 6;
+ }
+ else
+ {
+ rResultRect.Left() += 4;
+ rResultRect.Right() += 4;
+ }
+ break;
+ case PART_THUMB_VERT:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ {
+ rResultRect.Top() += 8;
+ rResultRect.Bottom() += 8;
+ }
+ else
+ {
+ rResultRect.Top() += 4;
+ rResultRect.Bottom() += 4;
+ }
+ break;
+ case PART_TRACK_HORZ_LEFT:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Right() += 8;
+ else
+ rResultRect.Right() += 4;
+ break;
+ case PART_TRACK_HORZ_RIGHT:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Left() += 6;
+ else
+ rResultRect.Left() += 4;
+ break;
+ case PART_TRACK_VERT_UPPER:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Bottom() += 8;
+ else
+ rResultRect.Bottom() += 4;
+ break;
+ case PART_TRACK_VERT_LOWER:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Top() += 8;
+ else
+ rResultRect.Top() += 4;
+ break;
+ default:
+ bRetVal = false;
+ }
+
+ return bRetVal;
+}
+
+/*
+ * IsNativeControlSupported()
+ * --------------------------
+ * Returns TRUE if the platform supports native
+ * drawing of the control defined by nPart.
+ *
+ */
+BOOL AquaSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
+{
+ bool bOk = FALSE;
+
+ // Native controls are now defaults
+ // If you want to disable experimental native controls code,
+ // just set the environment variable SAL_NO_NWF to something
+ // and vcl controls will be used as default again.
+
+ switch( nType )
+ {
+ case CTRL_PUSHBUTTON:
+ case CTRL_RADIOBUTTON:
+ case CTRL_CHECKBOX:
+ case CTRL_LISTNODE:
+ if( nPart == PART_ENTIRE_CONTROL )
+ return true;
+ break;
+
+ case CTRL_SCROLLBAR:
+ if( nPart == PART_DRAW_BACKGROUND_HORZ ||
+ nPart == PART_DRAW_BACKGROUND_VERT ||
+ nPart == PART_ENTIRE_CONTROL ||
+ nPart == HAS_THREE_BUTTONS )
+ return true;
+ break;
+
+ case CTRL_SLIDER:
+ if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
+ return true;
+ break;
+
+ case CTRL_EDITBOX:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == HAS_BACKGROUND_TEXTURE )
+ return true;
+ break;
+
+ case CTRL_MULTILINE_EDITBOX:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == HAS_BACKGROUND_TEXTURE )
+ return true;
+ break;
+
+ case CTRL_SPINBOX:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_ALL_BUTTONS ||
+ nPart == HAS_BACKGROUND_TEXTURE )
+ return true;
+ break;
+
+ case CTRL_SPINBUTTONS:
+ return false;
+ break;
+
+ case CTRL_COMBOBOX:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == HAS_BACKGROUND_TEXTURE )
+ return true;
+ break;
+
+ case CTRL_LISTBOX:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_WINDOW ||
+ nPart == HAS_BACKGROUND_TEXTURE ||
+ nPart == PART_SUB_EDIT
+ )
+ return true;
+ break;
+
+ case CTRL_TAB_ITEM:
+ case CTRL_TAB_PANE:
+ case CTRL_TAB_BODY: // see vcl/source/window/tabpage.cxx
+ case CTRL_FIXEDBORDER:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_TABS_DRAW_RTL ||
+ nPart == HAS_BACKGROUND_TEXTURE )
+ return true;
+ break;
+
+ // when PART_BUTTON is used, toolbar icons are not highlighted when mouse rolls over.
+ // More Aqua compliant
+ case CTRL_TOOLBAR:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_DRAW_BACKGROUND_HORZ ||
+ nPart == PART_DRAW_BACKGROUND_VERT)
+ return true;
+ break;
+
+ case CTRL_WINDOW_BACKGROUND:
+ if ( nPart == PART_BACKGROUND_WINDOW ||
+ nPart == PART_BACKGROUND_DIALOG )
+ return true;
+ break;
+
+ case CTRL_MENUBAR:
+ if( nPart == PART_ENTIRE_CONTROL )
+ return true;
+ break;
+
+ case CTRL_TOOLTIP: // ** TO DO
+ #if 0
+ if( nPart == PART_ENTIRE_CONTROL ) // we don't currently support the tooltip
+ return true;
+ #endif
+ break;
+
+ case CTRL_MENU_POPUP:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_MENU_ITEM ||
+ nPart == PART_MENU_ITEM_CHECK_MARK ||
+ nPart == PART_MENU_ITEM_RADIO_MARK)
+ return true;
+ break;
+ case CTRL_PROGRESS:
+ case CTRL_INTROPROGRESS:
+ if( nPart == PART_ENTIRE_CONTROL )
+ return true;
+ break;
+ case CTRL_FRAME:
+ if( nPart == PART_BORDER )
+ return true;
+ break;
+ case CTRL_LISTNET:
+ if( nPart == PART_ENTIRE_CONTROL )
+ return true;
+ break;
+ }
+
+ return bOk;
+}
+
+/*
+ * HitTestNativeControl()
+ *
+ * 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.
+ */
+BOOL AquaSalGraphics::hitTestNativeControl( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion,
+ const Point& rPos, BOOL& rIsInside )
+{
+ if ( nType == CTRL_SCROLLBAR )
+ {
+ Rectangle aRect;
+ bool bValid = AquaGetScrollRect( /* TODO: m_nScreen */ nPart, rControlRegion, aRect );
+ rIsInside = bValid ? aRect.IsInside( rPos ) : FALSE;
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ {
+ // in double max mode the actual trough is a little smaller than the track
+ // there is some visual filler that is not sensitive
+ if( bValid && rIsInside )
+ {
+ if( nPart == PART_TRACK_HORZ_AREA )
+ {
+ // the left 4 pixels are not hit sensitive
+ if( rPos.X() - aRect.Left() < 4 )
+ rIsInside = FALSE;
+ }
+ else if( nPart == PART_TRACK_VERT_AREA )
+ {
+ // the top 4 pixels are not hit sensitive
+ if( rPos.Y() - aRect.Top() < 4 )
+ rIsInside = FALSE;
+ }
+ }
+ }
+ return bValid;
+ } // CTRL_SCROLLBAR
+
+ return FALSE;
+}
+
+/*
+ kThemeStateInactive = 0,
+ kThemeStateActive = 1,
+ kThemeStatePressed = 2,
+ kThemeStateRollover = 6,
+ kThemeStateUnavailable = 7,
+ kThemeStateUnavailableInactive = 8
+ kThemeStatePressedUp = 2,
+ kThemeStatePressedDown = 3
+
+#define CTRL_STATE_ENABLED 0x0001
+#define CTRL_STATE_FOCUSED 0x0002
+#define CTRL_STATE_PRESSED 0x0004
+#define CTRL_STATE_ROLLOVER 0x0008
+#define CTRL_STATE_HIDDEN 0x0010
+#define CTRL_STATE_DEFAULT 0x0020
+#define CTRL_STATE_SELECTED 0x0040
+#define CTRL_CACHING_ALLOWED 0x8000 // set when the control is completely visible (i.e. not clipped)
+*/
+UInt32 AquaSalGraphics::getState( ControlState nState )
+{
+ bool bDrawActive = mpFrame ? ([mpFrame->getWindow() isKeyWindow] ? true : false) : true;
+ if( (nState & CTRL_STATE_ENABLED) == 0 || ! bDrawActive )
+ {
+ if( (nState & CTRL_STATE_HIDDEN) == 0 )
+ return kThemeStateInactive;
+ else
+ return kThemeStateUnavailableInactive;
+ }
+
+ if( (nState & CTRL_STATE_HIDDEN) != 0 )
+ return kThemeStateUnavailable;
+
+ if( (nState & CTRL_STATE_PRESSED) != 0 )
+ return kThemeStatePressed;
+
+ return kThemeStateActive;
+}
+
+UInt32 AquaSalGraphics::getTrackState( ControlState nState )
+{
+ bool bDrawActive = mpFrame ? ([mpFrame->getWindow() isKeyWindow] ? true : false) : true;
+ if( (nState & CTRL_STATE_ENABLED) == 0 || ! bDrawActive )
+ return kThemeTrackInactive;
+
+ return kThemeTrackActive;
+}
+
+/*
+ * DrawNativeControl()
+ *
+ * Draws the requested control described by nPart/nState.
+ *
+ * rControlRegion: The bounding region of the complete control in VCL frame coordinates.
+ * aValue: An optional value (tristate/numerical/string)
+ * aCaption: A caption or title string (like button text etc)
+ */
+BOOL AquaSalGraphics::drawNativeControl(ControlType nType,
+ ControlPart nPart,
+ const Rectangle& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const rtl::OUString& aCaption )
+{
+ BOOL bOK = FALSE;
+
+ if( ! CheckContext() )
+ return false;
+
+ CGContextSaveGState( mrContext );
+
+ Rectangle buttonRect = rControlRegion;
+ HIRect rc = ImplGetHIRectFromRectangle(buttonRect);
+
+ /** Scrollbar parts code equivalent **
+ PART_BUTTON_UP 101
+ PART_BUTTON_DOWN 102
+ PART_THUMB_VERT 211
+ PART_TRACK_VERT_UPPER 201
+ PART_TRACK_VERT_LOWER 203
+
+ PART_DRAW_BACKGROUND_HORZ 1000
+ PART_DRAW_BACKGROUND_VERT 1001
+ **/
+
+ switch( nType )
+ {
+
+ case CTRL_COMBOBOX:
+ if ( nPart == HAS_BACKGROUND_TEXTURE ||
+ nPart == PART_ENTIRE_CONTROL )
+ {
+ HIThemeButtonDrawInfo aComboInfo;
+ aComboInfo.version = 0;
+ aComboInfo.kind = kThemeComboBox;
+ aComboInfo.state = getState( nState );
+ aComboInfo.value = kThemeButtonOn;
+ aComboInfo.adornment = kThemeAdornmentNone;
+
+ if( (nState & CTRL_STATE_FOCUSED) != 0 )
+ aComboInfo.adornment |= kThemeAdornmentFocus;
+
+ HIThemeDrawButton(&rc, &aComboInfo, mrContext, kHIThemeOrientationNormal,&rc);
+ bOK = true;
+ }
+ break;
+
+ case CTRL_FIXEDBORDER:
+ case CTRL_TOOLBAR:
+ {
+ HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
+ aMenuItemDrawInfo.version = 0;
+ aMenuItemDrawInfo.state = kThemeMenuActive;
+ aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
+ HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,NULL);
+ bOK = true;
+ }
+ break;
+
+ case CTRL_WINDOW_BACKGROUND:
+ {
+ HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
+ aThemeBackgroundInfo.version = 0;
+ aThemeBackgroundInfo.state = getState( nState );
+ aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundInactive;
+ // FIXME: without this magical offset there is a 2 pixel black border on the right and bottom
+ rc.size.width += 2;
+ rc.size.height += 2;
+
+ HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, mrContext, kHIThemeOrientationNormal);
+ CGContextFillRect( mrContext, rc );
+ bOK = true;
+ }
+ break;
+
+ case CTRL_MENUBAR:
+ case CTRL_MENU_POPUP:
+ {
+ if ((nPart == PART_ENTIRE_CONTROL) || (nPart == PART_MENU_ITEM )|| (nPart == HAS_BACKGROUND_TEXTURE ))
+ {
+ // FIXME: without this magical offset there is a 2 pixel black border on the right
+ rc.size.width += 2;
+
+ HIThemeMenuDrawInfo aMenuInfo;
+ aMenuInfo.version = 0;
+ aMenuInfo.menuType = kThemeMenuTypePullDown;
+
+ HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
+ // the Aqua grey theme when the item is selected is drawn here.
+ aMenuItemDrawInfo.itemType = kThemeMenuItemPlain;
+
+ if ((nPart == PART_MENU_ITEM ) && (nState & CTRL_STATE_SELECTED))
+ {
+ // the blue theme when the item is selected is drawn here.
+ aMenuItemDrawInfo.state = kThemeMenuSelected;
+ }
+ else
+ {
+ // normal color for non selected item
+ aMenuItemDrawInfo.state = kThemeMenuActive;
+ }
+
+ // repaints the background of the pull down menu
+ HIThemeDrawMenuBackground(&rc,&aMenuInfo,mrContext,kHIThemeOrientationNormal);
+
+ // repaints the item either blue (selected) and/or Aqua grey (active only)
+ HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,&rc);
+
+ bOK = true;
+ }
+ else if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) {
+ if( nState & CTRL_STATE_PRESSED ) {//checked, else it is not displayed (see vcl/source/window/menu.cxx)
+ HIThemeTextInfo aTextInfo;
+ aTextInfo.version = 0;
+ aTextInfo.state = ((nState & CTRL_STATE_ENABLED)==0) ? kThemeStateInactive: kThemeStateActive;
+ aTextInfo.fontID = kThemeMenuItemMarkFont;
+ aTextInfo.horizontalFlushness=kHIThemeTextHorizontalFlushCenter;
+ aTextInfo.verticalFlushness=kHIThemeTextVerticalFlushTop;
+ aTextInfo.options=kHIThemeTextBoxOptionNone;
+ aTextInfo.truncationPosition=kHIThemeTextTruncationNone;
+ //aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone
+
+ if( nState & CTRL_STATE_SELECTED) aTextInfo.state = kThemeStatePressed; //item highlighted
+
+ UniChar mark=( nPart == PART_MENU_ITEM_CHECK_MARK ) ? kCheckUnicode: kBulletUnicode;//0x2713;
+ CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull);
+ HIThemeDrawTextBox(cfString, &rc, &aTextInfo, mrContext, kHIThemeOrientationNormal);
+ if (cfString)
+ CFRelease(cfString);
+
+ bOK = true;
+ }
+ }
+ }
+ break;
+
+ case CTRL_PUSHBUTTON:
+ {
+ // [ FIXME] : instead of use a value, vcl can retrieve corect values on the fly (to be implemented)
+ const int PB_Mini_Height = 15;
+ const int PB_Norm_Height = 21;
+
+ HIThemeButtonDrawInfo aPushInfo;
+ aPushInfo.version = 0;
+
+ // no animation
+ aPushInfo.animation.time.start = 0;
+ aPushInfo.animation.time.current = 0;
+ PushButtonValue* pPBVal = aValue.getType() == CTRL_PUSHBUTTON ? (PushButtonValue*)&aValue : NULL;
+ int nPaintHeight = static_cast<int>(rc.size.height);
+
+ if( pPBVal && pPBVal->mbBevelButton )
+ {
+ aPushInfo.kind = kThemeRoundedBevelButton;
+ }
+ else if( rc.size.height <= PB_Norm_Height )
+ {
+ aPushInfo.kind = kThemePushButtonMini;
+ nPaintHeight = PB_Mini_Height;
+ }
+ else if( pPBVal->mbSingleLine || rc.size.height < (PB_Norm_Height + PB_Norm_Height/2) )
+ {
+ aPushInfo.kind = kThemePushButtonNormal;
+ nPaintHeight = PB_Norm_Height;
+
+ // avoid clipping when focused
+ rc.origin.x += FOCUS_RING_WIDTH/2;
+ rc.size.width -= FOCUS_RING_WIDTH;
+
+ if( (nState & CTRL_STATE_DEFAULT) != 0 )
+ {
+ AquaBlinker::Blink( mpFrame, buttonRect );
+ // show correct animation phase
+ aPushInfo.animation.time.current = CFAbsoluteTimeGetCurrent();
+ }
+ }
+ else
+ aPushInfo.kind = kThemeBevelButton;
+
+ // translate the origin for controls with fixed paint height
+ // so content ends up somewhere sensible
+ int delta_y = static_cast<int>(rc.size.height) - nPaintHeight;
+ rc.origin.y += delta_y/2;
+
+ aPushInfo.state = getState( nState );
+ aPushInfo.value = ImplGetButtonValue( aValue.getTristateVal() );
+
+ aPushInfo.adornment = (( nState & CTRL_STATE_DEFAULT ) != 0) ?
+ kThemeAdornmentDefault :
+ kThemeAdornmentNone;
+ if( (nState & CTRL_STATE_FOCUSED) != 0 )
+ aPushInfo.adornment |= kThemeAdornmentFocus;
+
+ HIThemeDrawButton( &rc, &aPushInfo, mrContext, kHIThemeOrientationNormal, NULL );
+ bOK = true;
+ }
+ break;
+
+ case CTRL_RADIOBUTTON:
+ case CTRL_CHECKBOX:
+ {
+ HIThemeButtonDrawInfo aInfo;
+ aInfo.version = 0;
+ switch( nType )
+ {
+ case CTRL_RADIOBUTTON: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeRadioButton;
+ else aInfo.kind = kThemeSmallRadioButton;
+ break;
+ case CTRL_CHECKBOX: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeCheckBox;
+ else aInfo.kind = kThemeSmallCheckBox;
+ break;
+ }
+
+ aInfo.state = getState( nState );
+
+ ButtonValue aButtonValue = aValue.getTristateVal();
+ aInfo.value = ImplGetButtonValue( aButtonValue );
+
+ aInfo.adornment = (( nState & CTRL_STATE_DEFAULT ) != 0) ?
+ kThemeAdornmentDefault :
+ kThemeAdornmentNone;
+ if( (nState & CTRL_STATE_FOCUSED) != 0 )
+ aInfo.adornment |= kThemeAdornmentFocus;
+ HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL );
+ bOK = true;
+ }
+ break;
+
+ case CTRL_LISTNODE:
+ {
+ ButtonValue aButtonValue = aValue.getTristateVal();
+
+ if( Application::GetSettings().GetLayoutRTL() && aButtonValue == BUTTONVALUE_OFF )
+ {
+ // FIXME: a value of kThemeDisclosureLeft
+ // should draw a theme compliant left disclosure triangle
+ // sadly this does not seem to work, so we'll draw a left
+ // grey equilateral triangle here ourselves.
+ // Perhaps some other HIThemeButtonDrawInfo setting would do the trick ?
+
+ CGContextSetShouldAntialias( mrContext, true );
+ float aGrey[] = { 0.45, 0.45, 0.45, 1.0 };
+ CGContextSetFillColor( mrContext, aGrey );
+ CGContextBeginPath( mrContext );
+ float x = rc.origin.x + rc.size.width;
+ float y = rc.origin.y;
+ CGContextMoveToPoint( mrContext, x, y );
+ y += rc.size.height;
+ CGContextAddLineToPoint( mrContext, x, y );
+ x -= rc.size.height * 0.866; // cos( 30 degree ) is approx. 0.866
+ y -= rc.size.height/2;
+ CGContextAddLineToPoint( mrContext, x, y );
+ CGContextDrawPath( mrContext, kCGPathEOFill );
+ }
+ else
+ {
+ HIThemeButtonDrawInfo aInfo;
+ aInfo.version = 0;
+ aInfo.kind = kThemeDisclosureTriangle;
+ aInfo.value = kThemeDisclosureRight;
+ aInfo.state = getState( nState );
+
+ aInfo.adornment = kThemeAdornmentNone;
+
+ switch( aButtonValue ) {
+ case BUTTONVALUE_ON: aInfo.value = kThemeDisclosureDown;//expanded
+ break;
+ case BUTTONVALUE_OFF:
+ // FIXME: this should have drawn a theme compliant disclosure triangle
+ // (see above)
+ if( Application::GetSettings().GetLayoutRTL() )
+ {
+ aInfo.value = kThemeDisclosureLeft;//collapsed, RTL
+ }
+ break;
+ case BUTTONVALUE_DONTKNOW: //what to do?
+ default:
+ break;
+ }
+
+ HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL );
+ }
+ bOK = true;
+ }
+ break;
+
+ case CTRL_PROGRESS:
+ case CTRL_INTROPROGRESS:
+ {
+ long nProgressWidth = aValue.getNumericVal();
+ HIThemeTrackDrawInfo aTrackInfo;
+ aTrackInfo.version = 0;
+ aTrackInfo.kind = (rc.size.height > 10) ? kThemeProgressBarLarge : kThemeProgressBarMedium;
+ aTrackInfo.bounds = rc;
+ aTrackInfo.min = 0;
+ aTrackInfo.max = static_cast<SInt32>(rc.size.width);
+ aTrackInfo.value = nProgressWidth;
+ aTrackInfo.reserved = 0;
+ aTrackInfo.bounds.origin.y -= 2; // FIXME: magic for shadow
+ aTrackInfo.bounds.size.width -= 2; // FIXME: magic for shadow
+ aTrackInfo.attributes = kThemeTrackHorizontal;
+ if( Application::GetSettings().GetLayoutRTL() )
+ aTrackInfo.attributes |= kThemeTrackRightToLeft;
+ aTrackInfo.enableState = getTrackState( nState );
+ // the intro bitmap never gets key anyway; we want to draw that enabled
+ if( nType == CTRL_INTROPROGRESS )
+ aTrackInfo.enableState = kThemeTrackActive;
+ aTrackInfo.filler1 = 0;
+ aTrackInfo.trackInfo.progress.phase = static_cast<UInt8>(CFAbsoluteTimeGetCurrent()*10.0);
+
+ HIThemeDrawTrack( &aTrackInfo, NULL, mrContext, kHIThemeOrientationNormal );
+ bOK = true;
+ }
+ break;
+
+ case CTRL_SLIDER:
+ {
+ SliderValue* pSLVal = (SliderValue*)&aValue;
+
+ HIThemeTrackDrawInfo aTrackDraw;
+ aTrackDraw.kind = kThemeSliderMedium;
+ if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
+ {
+ aTrackDraw.bounds = rc;
+ aTrackDraw.min = pSLVal->mnMin;
+ aTrackDraw.max = pSLVal->mnMax;;
+ aTrackDraw.value = pSLVal->mnCur;
+ aTrackDraw.reserved = 0;
+ aTrackDraw.attributes = kThemeTrackShowThumb;
+ if( nPart == PART_TRACK_HORZ_AREA )
+ aTrackDraw.attributes |= kThemeTrackHorizontal;
+ aTrackDraw.enableState = (nState & CTRL_STATE_ENABLED)
+ ? kThemeTrackActive : kThemeTrackInactive;
+
+ SliderTrackInfo aSlideInfo;
+ aSlideInfo.thumbDir = kThemeThumbUpward;
+ aSlideInfo.pressState = 0;
+ aTrackDraw.trackInfo.slider = aSlideInfo;
+
+ HIThemeDrawTrack( &aTrackDraw, NULL, mrContext, kHIThemeOrientationNormal );
+ bOK = true;
+ }
+ }
+ break;
+
+ case CTRL_SCROLLBAR:
+ {
+ ScrollbarValue* pScrollbarVal = (ScrollbarValue *)&aValue;
+
+ if( nPart == PART_DRAW_BACKGROUND_VERT ||
+ nPart == PART_DRAW_BACKGROUND_HORZ )
+ {
+ HIThemeTrackDrawInfo aTrackDraw;
+ aTrackDraw.kind = kThemeMediumScrollBar;
+ // FIXME: the scrollbar length must be adjusted
+ if (nPart == PART_DRAW_BACKGROUND_VERT)
+ rc.size.height += 2;
+ else
+ rc.size.width += 2;
+
+ aTrackDraw.bounds = rc;
+ aTrackDraw.min = pScrollbarVal->mnMin;
+ aTrackDraw.max = pScrollbarVal->mnMax - pScrollbarVal->mnVisibleSize;
+ aTrackDraw.value = pScrollbarVal->mnCur;
+ aTrackDraw.reserved = 0;
+ aTrackDraw.attributes = kThemeTrackShowThumb;
+ if( nPart == PART_DRAW_BACKGROUND_HORZ )
+ aTrackDraw.attributes |= kThemeTrackHorizontal;
+ aTrackDraw.enableState = getTrackState( nState );
+
+ ScrollBarTrackInfo aScrollInfo;
+ aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize;
+ aScrollInfo.pressState = 0;
+
+ if ( pScrollbarVal->mnButton1State & CTRL_STATE_ENABLED )
+ {
+ if ( pScrollbarVal->mnButton1State & CTRL_STATE_PRESSED )
+ aScrollInfo.pressState = kThemeTopOutsideArrowPressed;
+ }
+
+ if ( pScrollbarVal->mnButton2State & CTRL_STATE_ENABLED )
+ {
+ if ( pScrollbarVal->mnButton2State & CTRL_STATE_PRESSED )
+ aScrollInfo.pressState = kThemeBottomOutsideArrowPressed;
+ }
+
+ if ( pScrollbarVal->mnThumbState & CTRL_STATE_ENABLED )
+ {
+ if ( pScrollbarVal->mnThumbState & CTRL_STATE_PRESSED )
+ aScrollInfo.pressState = kThemeThumbPressed;
+ }
+
+ aTrackDraw.trackInfo.scrollbar = aScrollInfo;
+
+ HIThemeDrawTrack( &aTrackDraw, NULL, mrContext, kHIThemeOrientationNormal );
+ bOK = true;
+ }
+ }
+ break;
+
+//#define OLD_TAB_STYLE
+#ifdef OLD_TAB_STYLE
+ case CTRL_TAB_PANE:
+ {
+ HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
+ aTabPaneDrawInfo.version = 0;
+ aTabPaneDrawInfo.state = kThemeStateActive;
+ aTabPaneDrawInfo.direction=kThemeTabNorth;
+ aTabPaneDrawInfo.size=kHIThemeTabSizeNormal;
+
+ //the border is outside the rect rc for Carbon
+ //but for VCL it should be inside
+ rc.origin.x+=1;
+ rc.size.width-=2;
+
+ HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal);
+ bOK = true;
+ }
+ break;
+
+ case CTRL_TAB_ITEM:
+ {
+ HIThemeTabDrawInfo aTabItemDrawInfo;
+ aTabItemDrawInfo.version=0;
+ aTabItemDrawInfo.style=kThemeTabNonFront;
+ aTabItemDrawInfo.direction=kThemeTabNorth;
+ aTabItemDrawInfo.size=kHIThemeTabSizeNormal;
+ aTabItemDrawInfo.adornment=kHIThemeTabAdornmentNone;
+
+ if(nState & CTRL_STATE_SELECTED) {
+ aTabItemDrawInfo.style=kThemeTabFront;
+ }
+ if(nState & CTRL_STATE_FOCUSED) {
+ aTabItemDrawInfo.adornment=kHIThemeTabAdornmentFocus;
+ }
+
+ /*if(rc.size.height>=TAB_HEIGHT_NORMAL) rc.size.height=TAB_HEIGHT_NORMAL;
+ else if(rc.size.height>=TAB_HEIGHT_SMALL) rc.size.height=TAB_HEIGHT_SMALL;
+ else rc.size.height=TAB_HEIGHT_MINI;*/
+ //now we only use the default size
+ rc.size.height=TAB_HEIGHT_NORMAL;
+
+ HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc );
+
+ bOK=true;
+ }
+ break;
+#else
+ case CTRL_TAB_PANE:
+ {
+ HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
+ aTabPaneDrawInfo.version = 1;
+ aTabPaneDrawInfo.state = kThemeStateActive;
+ aTabPaneDrawInfo.direction=kThemeTabNorth;
+ aTabPaneDrawInfo.size=kHIThemeTabSizeNormal;
+ aTabPaneDrawInfo.kind=kHIThemeTabKindNormal;
+
+ //the border is outside the rect rc for Carbon
+ //but for VCL it should be inside
+ rc.origin.x+=1;
+ rc.origin.y-=TAB_HEIGHT_NORMAL/2;
+ rc.size.height+=TAB_HEIGHT_NORMAL/2;
+ rc.size.width-=2;
+
+ HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal);
+
+ bOK = true;
+ }
+ break;
+
+ case CTRL_TAB_ITEM:
+ {
+ HIThemeTabDrawInfo aTabItemDrawInfo;
+ aTabItemDrawInfo.version=1;
+ aTabItemDrawInfo.style=kThemeTabNonFront;
+ aTabItemDrawInfo.direction=kThemeTabNorth;
+ aTabItemDrawInfo.size=kHIThemeTabSizeNormal;
+ aTabItemDrawInfo.adornment=kHIThemeTabAdornmentTrailingSeparator;
+ //State
+ if(nState & CTRL_STATE_SELECTED) {
+ aTabItemDrawInfo.style=kThemeTabFront;
+ }
+ if(nState & CTRL_STATE_FOCUSED) {
+ aTabItemDrawInfo.adornment|=kHIThemeTabAdornmentFocus;
+ }
+
+ //first, last or middle tab
+ aTabItemDrawInfo.position=kHIThemeTabPositionMiddle;
+
+ TabitemValue* pTabValue = (TabitemValue *) &aValue;
+ unsigned int nAlignment = pTabValue->mnAlignment;
+ //TABITEM_LEFTALIGNED (and TABITEM_RIGHTALIGNED) for the leftmost (or rightmost) tab
+ //when there are several lines of tabs because there is only one first tab and one
+ //last tab and TABITEM_FIRST_IN_GROUP (and TABITEM_LAST_IN_GROUP) because when the
+ //line width is different from window width, there may not be TABITEM_RIGHTALIGNED
+ if( ( (nAlignment & TABITEM_LEFTALIGNED)&&(nAlignment & TABITEM_RIGHTALIGNED) ) ||
+ ( (nAlignment & TABITEM_FIRST_IN_GROUP)&&(nAlignment & TABITEM_LAST_IN_GROUP) )
+ ) //tab alone
+ aTabItemDrawInfo.position=kHIThemeTabPositionOnly;
+ else if((nAlignment & TABITEM_LEFTALIGNED)||(nAlignment & TABITEM_FIRST_IN_GROUP))
+ aTabItemDrawInfo.position=kHIThemeTabPositionFirst;
+ else if((nAlignment & TABITEM_RIGHTALIGNED)||(nAlignment & TABITEM_LAST_IN_GROUP))
+ aTabItemDrawInfo.position=kHIThemeTabPositionLast;
+
+ //support for RTL
+ //see issue 79748
+ if( Application::GetSettings().GetLayoutRTL() ) {
+ if( aTabItemDrawInfo.position == kHIThemeTabPositionFirst )
+ aTabItemDrawInfo.position = kHIThemeTabPositionLast;
+ else if( aTabItemDrawInfo.position == kHIThemeTabPositionLast )
+ aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
+ }
+
+ rc.size.width+=2;//because VCL has 2 empty pixels between 2 tabs
+ rc.origin.x-=1;
+
+ HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc );
+
+ bOK=true;
+ }
+ break;
+#endif
+
+ case CTRL_LISTBOX:
+ switch( nPart)
+ {
+ case PART_ENTIRE_CONTROL:
+ case PART_BUTTON_DOWN:
+ {
+ HIThemeButtonDrawInfo aListInfo;
+ aListInfo.version = 0;
+ aListInfo.kind = kThemePopupButton;
+ aListInfo.state = getState( nState );//kThemeStateInactive -> greyed
+ aListInfo.value = kThemeButtonOn;
+
+ aListInfo.adornment = kThemeAdornmentDefault;
+ if( (nState & CTRL_STATE_FOCUSED) != 0 )
+ aListInfo.adornment |= kThemeAdornmentFocus;
+
+ HIThemeDrawButton(&rc, &aListInfo, mrContext, kHIThemeOrientationNormal,&rc);
+ bOK = true;
+ break;
+ }
+ case PART_WINDOW:
+ {
+ HIThemeFrameDrawInfo aTextDrawInfo;
+ aTextDrawInfo.version=0;
+ aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
+ aTextDrawInfo.state=getState( nState );
+ aTextDrawInfo.isFocused=false;
+
+ rc.size.width+=1;//else there's a white space because aqua theme hasn't a 3D border
+ rc.size.height+=1;
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
+
+ if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
+
+ bOK=true;
+ break;
+ }
+ }
+ break;
+
+ case CTRL_EDITBOX:
+ case CTRL_MULTILINE_EDITBOX:
+ {
+ HIThemeFrameDrawInfo aTextDrawInfo;
+ aTextDrawInfo.version=0;
+ aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
+ aTextDrawInfo.state=getState( nState );
+ aTextDrawInfo.isFocused=false;
+
+ rc.size.width += 1; // else there may be a white space because aqua theme hasn't a 3D border
+ // change rc so that the frame will encompass only the content region
+ // see counterpart in GetNativeControlRegion
+ rc.size.width += 2;
+ rc.size.height += 2;
+
+ //CGContextSetFillColorWithColor
+ CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
+ //fill a white background, because drawFrame only draws the border
+
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
+
+ if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
+
+ bOK=true;
+ }
+ break;
+
+ case CTRL_SPINBOX:
+ {
+ if(nPart == PART_ENTIRE_CONTROL)
+ {
+ //text field:
+ HIThemeFrameDrawInfo aTextDrawInfo;
+ aTextDrawInfo.version=0;
+ aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
+ aTextDrawInfo.state=getState( nState );
+ aTextDrawInfo.isFocused=false;
+
+ //rc.size.width contains the full size of the spinbox ie textfield + button
+ //so we remove the button width and the space between the button and the textfield
+ rc.size.width -= SPIN_BUTTON_SPACE + SPIN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
+ rc.origin.x += FOCUS_RING_WIDTH;
+ rc.origin.y += FOCUS_RING_WIDTH;
+
+ //CGContextSetFillColorWithColor
+ CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
+ //fill a white background, because drawFrame only draws the border
+
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
+
+ if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
+
+ //buttons:
+ SpinbuttonValue* pSpinButtonVal = (SpinbuttonValue *)&aValue;
+ ControlState nUpperState = CTRL_STATE_ENABLED;//state of the upper button
+ ControlState nLowerState = CTRL_STATE_ENABLED;//and of the lower button
+ if(pSpinButtonVal) {//pSpinButtonVal is sometimes null
+ nUpperState = (ControlState) pSpinButtonVal->mnUpperState;
+ nLowerState = (ControlState) pSpinButtonVal->mnLowerState;
+ }
+
+ if( pSpinButtonVal )
+ {
+ HIThemeButtonDrawInfo aSpinInfo;
+ aSpinInfo.kind = kThemeIncDecButton;
+ aSpinInfo.state = kThemeStateActive;
+ if(nUpperState & CTRL_STATE_PRESSED)
+ aSpinInfo.state = kThemeStatePressedUp;
+ else if(nLowerState & CTRL_STATE_PRESSED)
+ aSpinInfo.state = kThemeStatePressedDown;
+ else if((nUpperState & ~CTRL_STATE_ENABLED)||(nLowerState & ~CTRL_STATE_ENABLED))
+ aSpinInfo.state = kThemeStateInactive;
+ else if((nUpperState & CTRL_STATE_ROLLOVER)||(nLowerState & CTRL_STATE_ROLLOVER))
+ aSpinInfo.state = kThemeStateRollover;
+
+ Rectangle aSpinRect( pSpinButtonVal->maUpperRect );
+ aSpinRect.Union( pSpinButtonVal->maLowerRect );
+ HIRect buttonRc = ImplGetHIRectFromRectangle(aSpinRect);
+
+ // FIXME: without this fuzz factor there is some unwanted clipping
+ if( Application::GetSettings().GetLayoutRTL() )
+ buttonRc.origin.x -= FOCUS_RING_WIDTH - CLIP_FUZZ;
+ else
+ buttonRc.origin.x += FOCUS_RING_WIDTH + CLIP_FUZZ;
+
+ switch( aValue.getTristateVal() )
+ {
+ case BUTTONVALUE_ON: aSpinInfo.value = kThemeButtonOn;
+ break;
+ case BUTTONVALUE_OFF: aSpinInfo.value = kThemeButtonOff;
+ break;
+ case BUTTONVALUE_MIXED:
+ case BUTTONVALUE_DONTKNOW:
+ default: aSpinInfo.value = kThemeButtonMixed;
+ break;
+ }
+
+ aSpinInfo.adornment = ( ((nUpperState & CTRL_STATE_DEFAULT) != 0 ) ||
+ ((nLowerState & CTRL_STATE_DEFAULT) != 0 )) ?
+ kThemeAdornmentDefault :
+ kThemeAdornmentNone;
+ if( ((nUpperState & CTRL_STATE_FOCUSED) != 0 ) || ((nLowerState & CTRL_STATE_FOCUSED) != 0 ))
+ aSpinInfo.adornment |= kThemeAdornmentFocus;
+
+ HIThemeDrawButton( &buttonRc, &aSpinInfo, mrContext, kHIThemeOrientationNormal, NULL );
+ }
+
+ bOK=true;
+ }
+
+ }
+ break;
+
+ case CTRL_FRAME:
+ {
+ USHORT nStyle = aValue.getNumericVal();
+ if( nPart == PART_BORDER ) {
+ if(!( nStyle & FRAME_DRAW_MENU ) && !(nStyle & FRAME_DRAW_WINDOWBORDER) )
+ {
+ // #i84756# strange effects start to happen when HIThemeDrawFrame
+ // meets the border of the window. These can be avoided by clipping
+ // to the boundary of the frame
+ if( rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight-3 )
+ {
+ CGMutablePathRef rPath = CGPathCreateMutable();
+ CGPathAddRect( rPath, NULL, CGRectMake( 0, 0, mpFrame->maGeometry.nWidth-1, mpFrame->maGeometry.nHeight-1 ) );
+
+ CGContextBeginPath( mrContext );
+ CGContextAddPath( mrContext, rPath );
+ CGContextClip( mrContext );
+ CGPathRelease( rPath );
+ }
+
+ HIThemeFrameDrawInfo aTextDrawInfo;
+ aTextDrawInfo.version=0;
+ aTextDrawInfo.kind=kHIThemeFrameListBox;
+ aTextDrawInfo.state=kThemeStateActive;
+ aTextDrawInfo.isFocused=false;
+
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
+
+ bOK=true;
+ }
+ }
+ }
+ break;
+
+ case CTRL_LISTNET:
+ {
+ //do nothing as there isn't net for listviews on macos
+ bOK=true;
+ }
+ break;
+
+ }
+
+ CGContextRestoreGState( mrContext );
+
+ /* #i90291# in most cases invalidating the whole control region instead
+ of just the unclipped part of it is sufficient (and probably faster).
+ However for the window background we should not unnecessarily enlarge
+ the really changed rectangle since the difference is usually quite high
+ (the background is always drawn as a whole since we don't know anything
+ about its possible contents)
+ */
+ if( nType == CTRL_WINDOW_BACKGROUND )
+ {
+ CGRect aRect = { { 0, 0 }, { 0, 0 } };
+ if( mxClipPath )
+ aRect = CGPathGetBoundingBox( mxClipPath );
+ if( aRect.size.width != 0 && aRect.size.height != 0 )
+ buttonRect.Intersection( Rectangle( Point( static_cast<long int>(aRect.origin.x),
+ static_cast<long int>(aRect.origin.y) ),
+ Size( static_cast<long int>(aRect.size.width),
+ static_cast<long int>(aRect.size.height) ) ) );
+ }
+
+ RefreshRect( buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight() );
+
+ return bOK;
+}
+
+/*
+ * DrawNativeControlText()
+ *
+ * OPTIONAL. Draws the requested text for the control described by nPart/nState.
+ * Used if text not drawn by DrawNativeControl().
+ *
+ * rControlRegion: The bounding region of the complete control in VCL frame coordinates.
+ * aValue: An optional value (tristate/numerical/string)
+ * aCaption: A caption or title string (like button text etc)
+ */
+BOOL AquaSalGraphics::drawNativeControlText( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const rtl::OUString& aCaption )
+{
+ return( FALSE );
+}
+
+
+/*
+ * GetNativeControlRegion()
+ *
+ * If the return value is TRUE, rNativeBoundingRegion
+ * contains the true bounding region covered by the control
+ * including any adornment, while rNativeContentRegion contains the area
+ * within the control that can be safely drawn into without drawing over
+ * the borders of the control.
+ *
+ * rControlRegion: The bounding region of the control in VCL frame coordinates.
+ * aValue: An optional value (tristate/numerical/string)
+ * aCaption: A caption or title string (like button text etc)
+ */
+BOOL AquaSalGraphics::getNativeControlRegion( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue, const rtl::OUString& aCaption,
+ Rectangle &rNativeBoundingRegion, Rectangle &rNativeContentRegion )
+
+{
+ BOOL toReturn = FALSE;
+
+ Rectangle aCtrlBoundRect( rControlRegion );
+ short x = aCtrlBoundRect.Left();
+ short y = aCtrlBoundRect.Top();
+ short w, h;
+
+ sal_uInt8 nBorderCleanup = 0;
+
+ switch (nType)
+ {
+ case CTRL_SLIDER:
+ {
+ if( nPart == PART_THUMB_HORZ )
+ {
+ w = 19; // taken from HIG
+ h = aCtrlBoundRect.GetHeight();
+ rNativeBoundingRegion = rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ toReturn = true;
+ }
+ else if( nPart == PART_THUMB_VERT )
+ {
+ w = aCtrlBoundRect.GetWidth();
+ h = 18; // taken from HIG
+ rNativeBoundingRegion = rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ toReturn = true;
+ }
+ }
+ break;
+
+ case CTRL_SCROLLBAR:
+ {
+ Rectangle aRect;
+ if( AquaGetScrollRect( /* m_nScreen */ nPart, aCtrlBoundRect, aRect ) )
+ {
+ toReturn = TRUE;
+ rNativeBoundingRegion = aRect;
+ rNativeContentRegion = aRect;
+ }
+ }
+ break;
+
+ case CTRL_PUSHBUTTON:
+ case CTRL_RADIOBUTTON:
+ case CTRL_CHECKBOX:
+ {
+ if ( nType == CTRL_PUSHBUTTON )
+ {
+ w = aCtrlBoundRect.GetWidth();
+ h = aCtrlBoundRect.GetHeight();
+ }
+ else
+ {
+ // checkbox and radio borders need cleanup after unchecking them
+ nBorderCleanup = 4;
+
+ // TEXT_SEPARATOR to respect Aqua HIG
+ w = BUTTON_WIDTH + TEXT_SEPARATOR;
+ h = BUTTON_HEIGHT;
+
+ }
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h + nBorderCleanup) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+ }
+ break;
+ case CTRL_PROGRESS:
+ {
+ Rectangle aRect( aCtrlBoundRect );
+ if( aRect.GetHeight() < 16 )
+ aRect.Bottom() = aRect.Top() + 9; // values taken from HIG for medium progress
+ else
+ aRect.Bottom() = aRect.Top() + 15; // values taken from HIG for large progress
+ rNativeBoundingRegion = aRect;
+ rNativeContentRegion = aRect;
+ toReturn = TRUE;
+ }
+ break;
+
+ case CTRL_INTROPROGRESS:
+ {
+ Rectangle aRect( aCtrlBoundRect );
+ aRect.Bottom() = aRect.Top() + INTRO_PROGRESS_HEIGHT; // values taken from HIG for medium progress
+ rNativeBoundingRegion = aRect;
+ rNativeContentRegion = aRect;
+ toReturn = TRUE;
+ }
+ break;
+
+ case CTRL_TAB_ITEM:
+
+ w = aCtrlBoundRect.GetWidth() + 2*TAB_TEXT_OFFSET - 2*VCL_TAB_TEXT_OFFSET;
+
+#ifdef OLD_TAB_STYLE
+ h = TAB_HEIGHT_NORMAL;
+#else
+ h = TAB_HEIGHT_NORMAL+2;
+#endif
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+
+ break;
+
+ case CTRL_EDITBOX:
+ {
+ w = aCtrlBoundRect.GetWidth();
+ if( w < 3+2*FOCUS_RING_WIDTH )
+ w = 3+2*FOCUS_RING_WIDTH;
+ h = TEXT_EDIT_HEIGHT_NORMAL+2*FOCUS_RING_WIDTH;
+ if( h < aCtrlBoundRect.GetHeight() )
+ h = aCtrlBoundRect.GetHeight();
+
+ rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*(FOCUS_RING_WIDTH+1), h-2*(FOCUS_RING_WIDTH+1) ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+ }
+ break;
+ case CTRL_LISTBOX:
+ case CTRL_COMBOBOX:
+ {
+ if( nPart == PART_ENTIRE_CONTROL )
+ {
+ w = aCtrlBoundRect.GetWidth();
+ h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
+
+ rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*FOCUS_RING_WIDTH, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = TRUE;
+ }
+ else if( nPart == PART_BUTTON_DOWN )
+ {
+ w = aCtrlBoundRect.GetWidth();
+ if( w < 3+2*FOCUS_RING_WIDTH )
+ w = 3+2*FOCUS_RING_WIDTH;
+ h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
+
+ x += w-DROPDOWN_BUTTON_WIDTH - FOCUS_RING_WIDTH;
+ y += FOCUS_RING_WIDTH;
+ w = DROPDOWN_BUTTON_WIDTH;
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = true;
+ }
+ else if( nPart == PART_SUB_EDIT )
+ {
+ w = aCtrlBoundRect.GetWidth();
+ h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
+
+ x += FOCUS_RING_WIDTH;
+ x += 3; // add an offset for rounded borders
+ y += 2; // don't draw into upper border
+ y += FOCUS_RING_WIDTH;
+ w -= 3 + DROPDOWN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
+ if( nType == CTRL_LISTBOX )
+ w -= 9; // HIG specifies 9 units distance between dropdown button area and content
+ h -= 4; // don't draw into lower border
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = true;
+ }
+ }
+ break;
+ case CTRL_SPINBOX:
+ if( nPart == PART_ENTIRE_CONTROL ) {
+ w = aCtrlBoundRect.GetWidth();
+ if( w < 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH )
+ w = 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH;
+ h = TEXT_EDIT_HEIGHT_NORMAL;
+
+ rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y ), Size( w-2*FOCUS_RING_WIDTH, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = TRUE;
+ }
+ else if( nPart == PART_SUB_EDIT ) {
+ w = aCtrlBoundRect.GetWidth() - SPIN_BUTTON_SPACE - SPIN_BUTTON_WIDTH;
+ h = TEXT_EDIT_HEIGHT_NORMAL;
+ x += 4; // add an offset for rounded borders
+ y += 2; // don't draw into upper border
+ w -= 8; // offset for left and right rounded border
+ h -= 4; // don't draw into upper or ower border
+
+ rNativeContentRegion = Rectangle( Point( x + FOCUS_RING_WIDTH, y + FOCUS_RING_WIDTH ), Size( w - 2* FOCUS_RING_WIDTH, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = TRUE;
+ }
+ else if( nPart == PART_BUTTON_UP ) {
+ //aCtrlBoundRect.GetWidth() contains the width of the full control
+ //ie the width of the textfield + button
+ //x is the position of the left corner of the full control
+ x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
+ y += FOCUS_RING_WIDTH - CLIP_FUZZ;
+ w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
+ h = SPIN_UPPER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+ }
+ else if( nPart == PART_BUTTON_DOWN ) {
+ x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
+ y += SPIN_UPPER_BUTTON_HEIGHT + FOCUS_RING_WIDTH - CLIP_FUZZ;
+ w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
+ h = SPIN_LOWER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+ }
+ break;
+ case CTRL_FRAME:
+ {
+ USHORT nStyle = aValue.getNumericVal();
+ if( ( nPart == PART_BORDER ) &&
+ !( nStyle & (FRAME_DRAW_MENU | FRAME_DRAW_WINDOWBORDER | FRAME_DRAW_BORDERWINDOWBORDER) ) )
+ {
+ Rectangle aRect(aCtrlBoundRect);
+ if( nStyle & FRAME_DRAW_DOUBLEIN )
+ {
+ aRect.Left() += 1;
+ aRect.Top() += 1;
+ //rRect.Right() -= 1;
+ //rRect.Bottom() -= 1;
+ }
+ else
+ {
+ aRect.Left() += 1;
+ aRect.Top() += 1;
+ aRect.Right() -= 1;
+ aRect.Bottom() -= 1;
+ }
+
+ rNativeContentRegion = aRect;
+ rNativeBoundingRegion = aRect;
+
+ toReturn = TRUE;
+ }
+ }
+ break;
+
+ case CTRL_MENUBAR:
+ case CTRL_MENU_POPUP:
+ {
+ if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) {
+
+ w=10;
+ h=10;//dimensions of the mark (10px font)
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+ }
+ }
+ break;
+
+ }
+
+ return toReturn;
+}