From 9d31d8f1d8d3a73f8c07ca39f5ed45e2bb7b088c Mon Sep 17 00:00:00 2001 From: Thorsten Wagner Date: Wed, 1 Jan 2020 14:43:38 +0100 Subject: tdf#125536 macOS native Carbon widgets reworked Change-Id: Id60895a48f59cb3c55db39d18cd27fed2108727e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/86066 Tested-by: Jenkins Reviewed-by: Noel Grandin --- vcl/osx/salnativewidgets.cxx | 1625 +++++++++++++++++++----------------------- 1 file changed, 734 insertions(+), 891 deletions(-) (limited to 'vcl/osx') diff --git a/vcl/osx/salnativewidgets.cxx b/vcl/osx/salnativewidgets.cxx index 6e94cd3e4df3..5248251480c5 100644 --- a/vcl/osx/salnativewidgets.cxx +++ b/vcl/osx/salnativewidgets.cxx @@ -36,6 +36,22 @@ #include "cuidraw.hxx" +// presentation of native widgets consists of two important methods: + +// AquaSalGraphics::getNativeControlRegion to determine native rectangle in pixels to draw the widget +// AquaSalGraphics::drawNativeControl to do the drawing operation itself + +// getNativeControlRegion has to calculate a content rectangle within it is safe to draw the widget. Furthermore a boundig rectangle +// has to be calculated by getNativeControlRegion to consider adornments like a focus rectangle. As drawNativeControl uses Carbon +// API calls, all widgets are drawn without text. Drawing of text is done separately by VCL on top of graphical Carbon widget +// representation. drawNativeControl is called by VCL using content rectangle determined by getNativeControlRegion. + +// FIXME: when calculation bounding rectangle larger then content rectangle, text displayed by VCL will become misaligned. To avoid +// misalignment bounding rectangle and content rectangle are calculated equally including adornments. Reduction of size for content +// is done by drawNativeControl subsequently. Only exception is editbox: As other widgets have distinct ControlPart::SubEdit control +// parts, editbox bounding rectangle and content rectangle are both calculated to reflect content area. Extending size for +// adornments is done by drawNativeControl subsequently. + #if !HAVE_FEATURE_MACOSX_SANDBOX @interface NSWindow(CoreUIRendererPrivate) @@ -44,8 +60,6 @@ #endif -// Helper returns an HIRect - static HIRect ImplGetHIRectFromRectangle(tools::Rectangle aRect) { HIRect aHIRect; @@ -56,19 +70,17 @@ static HIRect ImplGetHIRectFromRectangle(tools::Rectangle aRect) return aHIRect; } -static ThemeButtonValue ImplGetButtonValue( ButtonValue aButtonValue ) +static ThemeButtonValue ImplGetButtonValue(ButtonValue aButtonValue) { - switch( aButtonValue ) + switch (aButtonValue) { case ButtonValue::On: return kThemeButtonOn; break; - case ButtonValue::Off: case ButtonValue::DontKnow: return kThemeButtonOff; break; - case ButtonValue::Mixed: default: return kThemeButtonMixed; @@ -76,30 +88,25 @@ static ThemeButtonValue ImplGetButtonValue( ButtonValue aButtonValue ) } } -static bool AquaGetScrollRect( /* TODO: int nScreen, */ ControlPart nPart, - const tools::Rectangle& rControlRect, tools::Rectangle& rResultRect ) +static bool AquaGetScrollRect(/* TODO: int nScreen, */ + ControlPart nPart, const tools::Rectangle &rControlRect, tools::Rectangle &rResultRect) { bool bRetVal = true; rResultRect = rControlRect; - - switch( nPart ) + switch (nPart) { case ControlPart::ButtonUp: - rResultRect.SetBottom( rResultRect.Top() ); + rResultRect.SetBottom(rResultRect.Top()); break; - case ControlPart::ButtonDown: - rResultRect.SetTop( rResultRect.Bottom() ); + rResultRect.SetTop(rResultRect.Bottom()); break; - case ControlPart::ButtonLeft: - rResultRect.SetRight( rResultRect.Left() ); + rResultRect.SetRight(rResultRect.Left()); break; - case ControlPart::ButtonRight: - rResultRect.SetLeft( rResultRect.Right() ); + rResultRect.SetLeft(rResultRect.Right()); break; - case ControlPart::TrackHorzArea: case ControlPart::TrackVertArea: case ControlPart::ThumbHorz: @@ -112,1144 +119,988 @@ static bool AquaGetScrollRect( /* TODO: int nScreen, */ ControlPart nPart, default: bRetVal = false; } - return bRetVal; } -bool AquaSalGraphics::isNativeControlSupported( ControlType nType, ControlPart nPart ) +bool AquaSalGraphics::isNativeControlSupported(ControlType nType, ControlPart nPart) { - // 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. + // native controls are now defaults. If you want to disable native controls, set the environment variable SAL_NO_NWF to + // something and VCL controls will be used as default again. - switch( nType ) + switch (nType) { case ControlType::Pushbutton: case ControlType::Radiobutton: case ControlType::Checkbox: case ControlType::ListNode: - if( nPart == ControlPart::Entire ) + if (nPart == ControlPart::Entire) return true; break; - case ControlType::Scrollbar: - if( nPart == ControlPart::DrawBackgroundHorz || - nPart == ControlPart::DrawBackgroundVert || - nPart == ControlPart::Entire || - nPart == ControlPart::HasThreeButtons ) + if (nPart == ControlPart::DrawBackgroundHorz || nPart == ControlPart::DrawBackgroundVert + || nPart == ControlPart::Entire || nPart == ControlPart::HasThreeButtons) return true; break; - case ControlType::Slider: - if( nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea ) + if (nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea) return true; break; - case ControlType::Editbox: - if( nPart == ControlPart::Entire || - nPart == ControlPart::HasBackgroundTexture ) + if (nPart == ControlPart::Entire || nPart == ControlPart::HasBackgroundTexture) return true; break; - case ControlType::MultilineEditbox: - if( nPart == ControlPart::Entire || - nPart == ControlPart::HasBackgroundTexture ) + if (nPart == ControlPart::Entire || nPart == ControlPart::HasBackgroundTexture) return true; break; - case ControlType::Spinbox: - if( nPart == ControlPart::Entire || - nPart == ControlPart::AllButtons || - nPart == ControlPart::HasBackgroundTexture ) + if (nPart == ControlPart::Entire || nPart == ControlPart::AllButtons || nPart == ControlPart::HasBackgroundTexture) return true; break; - case ControlType::SpinButtons: - return false; + return false; break; - case ControlType::Combobox: - if( nPart == ControlPart::Entire || - nPart == ControlPart::HasBackgroundTexture ) + if (nPart == ControlPart::Entire || nPart == ControlPart::HasBackgroundTexture) return true; break; - case ControlType::Listbox: - if( nPart == ControlPart::Entire || - nPart == ControlPart::ListboxWindow || - nPart == ControlPart::HasBackgroundTexture || - nPart == ControlPart::SubEdit - ) + if (nPart == ControlPart::Entire || nPart == ControlPart::ListboxWindow || nPart == ControlPart::HasBackgroundTexture + || nPart == ControlPart::SubEdit) return true; break; - case ControlType::TabItem: case ControlType::TabPane: - case ControlType::TabBody: // see vcl/source/window/tabpage.cxx - if( nPart == ControlPart::Entire || - nPart == ControlPart::TabsDrawRtl || - nPart == ControlPart::HasBackgroundTexture ) + case ControlType::TabBody: + if (nPart == ControlPart::Entire || nPart == ControlPart::TabsDrawRtl || nPart == ControlPart::HasBackgroundTexture) return true; break; - - // when ControlPart::Button is used, toolbar icons are not highlighted when mouse rolls over. - // More Aqua compliant case ControlType::Toolbar: - if( nPart == ControlPart::Entire || - nPart == ControlPart::DrawBackgroundHorz || - nPart == ControlPart::DrawBackgroundVert) + if (nPart == ControlPart::Entire || nPart == ControlPart::DrawBackgroundHorz + || nPart == ControlPart::DrawBackgroundVert) return true; break; - case ControlType::WindowBackground: - if ( nPart == ControlPart::BackgroundWindow || - nPart == ControlPart::BackgroundDialog ) + if (nPart == ControlPart::BackgroundWindow || nPart == ControlPart::BackgroundDialog) return true; break; - case ControlType::Menubar: - if( nPart == ControlPart::Entire ) + if (nPart == ControlPart::Entire) return true; break; - - case ControlType::Tooltip: // ** TO DO + case ControlType::Tooltip: if (nPart == ControlPart::Entire) return true; break; - case ControlType::MenuPopup: - if( nPart == ControlPart::Entire || - nPart == ControlPart::MenuItem || - nPart == ControlPart::MenuItemCheckMark || - nPart == ControlPart::MenuItemRadioMark) + if (nPart == ControlPart::Entire || nPart == ControlPart::MenuItem || nPart == ControlPart::MenuItemCheckMark + || nPart == ControlPart::MenuItemRadioMark) return true; break; case ControlType::Progress: case ControlType::IntroProgress: - if( nPart == ControlPart::Entire ) + if (nPart == ControlPart::Entire) return true; break; case ControlType::Frame: - if( nPart == ControlPart::Border ) + if (nPart == ControlPart::Border) return true; break; case ControlType::ListNet: - if( nPart == ControlPart::Entire ) + if (nPart == ControlPart::Entire) return true; break; - default: break; + default: + break; } - return false; } -bool AquaSalGraphics::hitTestNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, - const Point& rPos, bool& rIsInside ) +bool AquaSalGraphics::hitTestNativeControl(ControlType nType, ControlPart nPart, const tools::Rectangle &rControlRegion, + const Point &rPos, bool& rIsInside) { - if ( nType == ControlType::Scrollbar ) + if (nType == ControlType::Scrollbar) { tools::Rectangle aRect; - bool bValid = AquaGetScrollRect( /* TODO: m_nScreen */ nPart, rControlRegion, aRect ); - rIsInside = bValid && aRect.IsInside( rPos ); + bool bValid = AquaGetScrollRect(/* TODO: int nScreen, */ + nPart, rControlRegion, aRect); + rIsInside = bValid && aRect.IsInside(rPos); return bValid; - } // ControlType::Scrollbar - + } return false; } -/* - kThemeStateInactive = 0, - kThemeStateActive = 1, - kThemeStatePressed = 2, - kThemeStateRollover = 6, - kThemeStateUnavailable = 7, - kThemeStateUnavailableInactive = 8 - kThemeStatePressedUp = 2, - kThemeStatePressedDown = 3 -*/ -UInt32 AquaSalGraphics::getState( ControlState nState ) +UInt32 AquaSalGraphics::getState(ControlState nState) { const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow]; - if( !(nState & ControlState::ENABLED) || ! bDrawActive ) + if (!(nState & ControlState::ENABLED) || !bDrawActive) { return kThemeStateInactive; } - - if( nState & ControlState::PRESSED ) + if (nState & ControlState::PRESSED) return kThemeStatePressed; - return kThemeStateActive; } -UInt32 AquaSalGraphics::getTrackState( ControlState nState ) +UInt32 AquaSalGraphics::getTrackState(ControlState nState) { const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow]; - if( ! (nState & ControlState::ENABLED) || ! bDrawActive ) - return kThemeTrackInactive; - + if (!(nState & ControlState::ENABLED) || !bDrawActive) + return kThemeTrackInactive; return kThemeTrackActive; } bool AquaSalGraphics::drawNativeControl(ControlType nType, - ControlPart nPart, - const tools::Rectangle& rControlRegion, - ControlState nState, - const ImplControlValue& aValue, - const OUString& ) + ControlPart nPart, + const tools::Rectangle &rControlRegion, + ControlState nState, + const ImplControlValue &aValue, + const OUString &) { bool bOK = false; - - if( ! CheckContext() ) + if (!CheckContext()) return false; - maContextHolder.saveState(); - tools::Rectangle buttonRect = rControlRegion; HIRect rc = ImplGetHIRectFromRectangle(buttonRect); - - switch( nType ) + switch (nType) { - - case ControlType::Combobox: - if ( nPart == ControlPart::HasBackgroundTexture || - nPart == ControlPart::Entire ) - { - HIThemeButtonDrawInfo aComboInfo; - aComboInfo.version = 0; - aComboInfo.kind = kThemeComboBox; - aComboInfo.state = getState( nState ); - aComboInfo.value = kThemeButtonOn; - aComboInfo.adornment = kThemeAdornmentNone; - - if( nState & ControlState::FOCUSED ) - aComboInfo.adornment |= kThemeAdornmentFocus; - - HIThemeDrawButton(&rc, &aComboInfo, maContextHolder.get(), kHIThemeOrientationNormal,&rc); - bOK = true; - } - break; - - case ControlType::Toolbar: - { -#if HAVE_FEATURE_MACOSX_SANDBOX - HIThemeMenuItemDrawInfo aMenuItemDrawInfo; - aMenuItemDrawInfo.version = 0; - aMenuItemDrawInfo.state = kThemeMenuActive; - aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground; - HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,maContextHolder.get(),kHIThemeOrientationNormal,NULL); -#else - if (rControlRegion.Top() == 0 && nPart == ControlPart::DrawBackgroundHorz) - { - const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow]; - CGFloat unifiedHeight = rControlRegion.GetHeight(); - CGRect drawRect = CGRectMake(rControlRegion.Left(), rControlRegion.Top(), rControlRegion.GetWidth(), rControlRegion.GetHeight()); - CUIDraw([NSWindow coreUIRenderer], drawRect, maContextHolder.get(), - reinterpret_cast([NSDictionary dictionaryWithObjectsAndKeys: - @"kCUIWidgetWindowFrame", @"widget", - @"regularwin", @"windowtype", - (bDrawActive ? @"normal" : @"inactive"), @"state", - [NSNumber numberWithDouble:unifiedHeight], @"kCUIWindowFrameUnifiedTitleBarHeightKey", - [NSNumber numberWithBool:NO], @"kCUIWindowFrameDrawTitleSeparatorKey", - [NSNumber numberWithBool:YES], @"is.flipped", - nil]), - nil); - } - else + case ControlType::Toolbar: { +#if HAVE_FEATURE_MACOSX_SANDBOX HIThemeMenuItemDrawInfo aMenuItemDrawInfo; aMenuItemDrawInfo.version = 0; aMenuItemDrawInfo.state = kThemeMenuActive; aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground; HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); - } +#else + if (rControlRegion.Top() == 0 && nPart == ControlPart::DrawBackgroundHorz) + { + const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow]; + CGFloat unifiedHeight = rControlRegion.GetHeight(); + CGRect drawRect = CGRectMake(rControlRegion.Left(), rControlRegion.Top(), + rControlRegion.GetWidth(), rControlRegion.GetHeight()); + CUIDraw([NSWindow coreUIRenderer], drawRect, maContextHolder.get(), + reinterpret_cast([NSDictionary dictionaryWithObjectsAndKeys: + @"kCUIWidgetWindowFrame", + @"widget", + @"regularwin", + @"windowtype", + (bDrawActive ? @"normal" : @"inactive"), + @"state", + [NSNumber numberWithDouble:unifiedHeight], + @"kCUIWindowFrameUnifiedTitleBarHeightKey", + [NSNumber numberWithBool:NO], + @"kCUIWindowFrameDrawTitleSeparatorKey", + [NSNumber numberWithBool:YES], + @"is.flipped", + nil]), + nil); + } + else + { + HIThemeMenuItemDrawInfo aMenuItemDrawInfo; + aMenuItemDrawInfo.version = 0; + aMenuItemDrawInfo.state = kThemeMenuActive; + aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground; + HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); + } #endif - bOK = true; - } - break; - + bOK = true; + } + break; case ControlType::WindowBackground: - { - HIThemeBackgroundDrawInfo aThemeBackgroundInfo; - aThemeBackgroundInfo.version = 0; - aThemeBackgroundInfo.state = getState( nState ); - aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundActive; - // 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, maContextHolder.get(), kHIThemeOrientationNormal); - CGContextFillRect( maContextHolder.get(), rc ); - bOK = true; - } - break; + { + HIThemeBackgroundDrawInfo aThemeBackgroundInfo; + aThemeBackgroundInfo.version = 0; + aThemeBackgroundInfo.state = getState(nState); + aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundActive; - case ControlType::Tooltip: - { - HIThemeBackgroundDrawInfo aThemeBackgroundInfo; - aThemeBackgroundInfo.version = 0; - aThemeBackgroundInfo.state = getState( nState ); - aThemeBackgroundInfo.kind = kThemeBrushAlertBackgroundActive; - rc.size.width += 2; - rc.size.height += 2; - - HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, maContextHolder.get(), kHIThemeOrientationNormal); - CGContextFillRect( maContextHolder.get(), rc ); - bOK = true; - } - break; + // FIXME: without this magical offset there is a 2 pixel black border on the right and bottom - case ControlType::Menubar: - case ControlType::MenuPopup: - { - if ((nPart == ControlPart::Entire) || (nPart == ControlPart::MenuItem )|| (nPart == ControlPart::HasBackgroundTexture )) + rc.size.width += 2; + rc.size.height += 2; + HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, maContextHolder.get(), kHIThemeOrientationNormal); + CGContextFillRect(maContextHolder.get(), rc); + bOK = true; + } + break; + case ControlType::Tooltip: { - // FIXME: without this magical offset there is a 2 pixel black border on the right + HIThemeBackgroundDrawInfo aThemeBackgroundInfo; + aThemeBackgroundInfo.version = 0; + aThemeBackgroundInfo.state = getState(nState); + aThemeBackgroundInfo.kind = kThemeBrushAlertBackgroundActive; rc.size.width += 2; + rc.size.height += 2; + HIThemeApplyBackground(&rc, &aThemeBackgroundInfo, maContextHolder.get(), kHIThemeOrientationNormal); + CGContextFillRect(maContextHolder.get(), rc); + bOK = true; + } + break; + case ControlType::Menubar: + case ControlType::MenuPopup: + if (nPart == ControlPart::Entire || nPart == ControlPart::MenuItem || nPart == ControlPart::HasBackgroundTexture) + { + // 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. + + // grey theme when the item is selected is drawn here. + aMenuItemDrawInfo.itemType = kThemeMenuItemPlain; + if ((nPart == ControlPart::MenuItem) && (nState & ControlState::SELECTED)) + + // blue theme when the item is selected is drawn here. - if ((nPart == ControlPart::MenuItem ) && (nState & ControlState::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,maContextHolder.get(),kHIThemeOrientationNormal); - // repaints the item either blue (selected) and/or Aqua grey (active only) - HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,maContextHolder.get(),kHIThemeOrientationNormal,&rc); + HIThemeDrawMenuBackground(&rc, &aMenuInfo,maContextHolder.get(), kHIThemeOrientationNormal); + + // repaints the item either blue (selected) and/or grey (active only) + HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, &rc); bOK = true; } - else if(( nPart == ControlPart::MenuItemCheckMark )||( nPart == ControlPart::MenuItemRadioMark )) { - if( nState & ControlState::PRESSED ) {//checked, else it is not displayed (see vcl/source/window/menu.cxx) + else if (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark) + { + + // checked, else it is not displayed (see vcl/source/window/menu.cxx) + + if (nState & ControlState::PRESSED) + { HIThemeTextInfo aTextInfo; aTextInfo.version = 0; aTextInfo.state = (nState & ControlState::ENABLED) ? kThemeStateInactive: kThemeStateActive; aTextInfo.fontID = kThemeMenuItemMarkFont; - aTextInfo.horizontalFlushness=kHIThemeTextHorizontalFlushCenter; - aTextInfo.verticalFlushness=kHIThemeTextVerticalFlushTop; - aTextInfo.options=kHIThemeTextBoxOptionNone; - aTextInfo.truncationPosition=kHIThemeTextTruncationNone; - //aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone + aTextInfo.horizontalFlushness = kHIThemeTextHorizontalFlushCenter; + aTextInfo.verticalFlushness = kHIThemeTextVerticalFlushTop; + aTextInfo.options = kHIThemeTextBoxOptionNone; + aTextInfo.truncationPosition = kHIThemeTextTruncationNone; - if( nState & ControlState::SELECTED) aTextInfo.state = kThemeStatePressed; //item highlighted + // aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone item highlighted - UniChar mark=( nPart == ControlPart::MenuItemCheckMark ) ? kCheckUnicode: kBulletUnicode;//0x2713; + if (nState & ControlState::SELECTED) aTextInfo.state = kThemeStatePressed; + UniChar mark=(nPart == ControlPart::MenuItemCheckMark) ? kCheckUnicode: kBulletUnicode; CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull); HIThemeDrawTextBox(cfString, &rc, &aTextInfo, maContextHolder.get(), kHIThemeOrientationNormal); if (cfString) CFRelease(cfString); - bOK = true; } } - } - break; - - case ControlType::Pushbutton: - { - // [ FIXME] : instead of use a value, vcl can retrieve correct 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 const * pPBVal = aValue.getType() == ControlType::Pushbutton ? static_cast(&aValue) : nullptr; - int nPaintHeight = static_cast(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 && pPBVal->mbSingleLine) || rc.size.height < (PB_Norm_Height + PB_Norm_Height/2) ) + break; + case ControlType::Pushbutton: { - aPushInfo.kind = kThemePushButtonNormal; - nPaintHeight = PB_Norm_Height; - - // avoid clipping when focused - rc.origin.x += FOCUS_RING_WIDTH/2; - rc.size.width -= FOCUS_RING_WIDTH; - } - else - aPushInfo.kind = kThemeBevelButton; - // translate the origin for controls with fixed paint height - // so content ends up somewhere sensible - int delta_y = static_cast(rc.size.height) - nPaintHeight; - rc.origin.y += delta_y/2; + // FIXME: instead of use a value, VCL can retrieve correct values on the fly (to be implemented) - aPushInfo.state = getState( nState ); - aPushInfo.value = ImplGetButtonValue( aValue.getTristateVal() ); + HIThemeButtonDrawInfo aPushInfo; + aPushInfo.version = 0; - aPushInfo.adornment = ( nState & ControlState::DEFAULT ) ? - kThemeAdornmentDefault : - kThemeAdornmentNone; - if( nState & ControlState::FOCUSED ) - aPushInfo.adornment |= kThemeAdornmentFocus; + // no animation - HIThemeDrawButton( &rc, &aPushInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr ); - bOK = true; - } - break; - - case ControlType::Radiobutton: - case ControlType::Checkbox: - { - HIThemeButtonDrawInfo aInfo; - aInfo.version = 0; - switch( nType ) - { - case ControlType::Radiobutton: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeRadioButton; - else aInfo.kind = kThemeSmallRadioButton; - break; - case ControlType::Checkbox: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeCheckBox; - else aInfo.kind = kThemeSmallCheckBox; - break; - default: break; - } - - aInfo.state = getState( nState ); + aPushInfo.animation.time.start = 0; + aPushInfo.animation.time.current = 0; + PushButtonValue const *pPBVal = aValue.getType() == ControlType::Pushbutton ? + static_cast(&aValue) : nullptr; + int nPaintHeight = static_cast(rc.size.height); + if (pPBVal && pPBVal->mbBevelButton) + { + aPushInfo.kind = kThemeRoundedBevelButton; + } + else if (rc.size.height <= PUSH_BUTTON_NORMAL_HEIGHT) + { + aPushInfo.kind = kThemePushButtonMini; + nPaintHeight = PUSH_BUTTON_SMALL_HEIGHT; + } + else if ((pPBVal && pPBVal->mbSingleLine) || rc.size.height < PUSH_BUTTON_NORMAL_HEIGHT * 3 / 2) + { + aPushInfo.kind = kThemePushButtonNormal; + nPaintHeight = PUSH_BUTTON_NORMAL_HEIGHT; - ButtonValue aButtonValue = aValue.getTristateVal(); - aInfo.value = ImplGetButtonValue( aButtonValue ); + // avoid clipping when focused - aInfo.adornment = ( nState & ControlState::DEFAULT ) ? - kThemeAdornmentDefault : - kThemeAdornmentNone; - if( nState & ControlState::FOCUSED ) - aInfo.adornment |= kThemeAdornmentFocus; - HIThemeDrawButton( &rc, &aInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr ); - bOK = true; - } - break; + rc.origin.x += FOCUS_RING_WIDTH / 2; + rc.size.width -= FOCUS_RING_WIDTH; + } + else + aPushInfo.kind = kThemeBevelButton; - case ControlType::ListNode: - { - ButtonValue aButtonValue = aValue.getTristateVal(); + // translate the origin for controls with fixed paint height so content ends up somewhere sensible - if( AllSettings::GetLayoutRTL() && aButtonValue == ButtonValue::Off ) + rc.origin.y += (rc.size.height - nPaintHeight) / 2; + aPushInfo.state = getState(nState); + aPushInfo.value = ImplGetButtonValue(aValue.getTristateVal()); + aPushInfo.adornment = (nState & ControlState::DEFAULT) ? kThemeAdornmentDefault : kThemeAdornmentNone; + if (nState & ControlState::FOCUSED) + aPushInfo.adornment |= kThemeAdornmentFocus; + HIThemeDrawButton(&rc, &aPushInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); + bOK = true; + } + break; + case ControlType::Radiobutton: + case ControlType::Checkbox: { - // 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( maContextHolder.get(), true ); - CGFloat const aGrey[] = { 0.45, 0.45, 0.45, 1.0 }; - CGContextSetFillColor( maContextHolder.get(), aGrey ); - CGContextBeginPath( maContextHolder.get() ); - float x = rc.origin.x + rc.size.width; - float y = rc.origin.y; - CGContextMoveToPoint( maContextHolder.get(), x, y ); - y += rc.size.height; - CGContextAddLineToPoint( maContextHolder.get(), x, y ); - x -= rc.size.height * 0.866; // cos( 30 degree ) is approx. 0.866 - y -= rc.size.height/2; - CGContextAddLineToPoint( maContextHolder.get(), x, y ); - CGContextDrawPath( maContextHolder.get(), kCGPathEOFill ); + HIThemeButtonDrawInfo aInfo; + aInfo.version = 0; + switch (nType) + { + case ControlType::Radiobutton: + if (rc.size.width >= RADIO_BUTTON_SMALL_SIZE) + aInfo.kind = kThemeRadioButton; + else + aInfo.kind = kThemeSmallRadioButton; + break; + case ControlType::Checkbox: + if (rc.size.width >= CHECKBOX_SMALL_SIZE) + aInfo.kind = kThemeCheckBox; + else + aInfo.kind = kThemeSmallCheckBox; + break; + default: + break; + } + aInfo.state = getState(nState); + ButtonValue aButtonValue = aValue.getTristateVal(); + aInfo.value = ImplGetButtonValue(aButtonValue); + aInfo.adornment = (nState & ControlState::DEFAULT) ? kThemeAdornmentDefault : kThemeAdornmentNone; + if (nState & ControlState::FOCUSED) + aInfo.adornment |= kThemeAdornmentFocus; + rc.size.width -= 2 * FOCUS_RING_WIDTH; + rc.size.height = RADIO_BUTTON_SMALL_SIZE; + rc.origin.x += FOCUS_RING_WIDTH; + rc.origin.y += FOCUS_RING_WIDTH; + HIThemeDrawButton(&rc, &aInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); + bOK = true; } - else + break; + case ControlType::ListNode: { + ButtonValue aButtonValue = aValue.getTristateVal(); HIThemeButtonDrawInfo aInfo; aInfo.version = 0; aInfo.kind = kThemeDisclosureTriangle; aInfo.value = kThemeDisclosureRight; - aInfo.state = getState( nState ); - + aInfo.state = getState(nState); aInfo.adornment = kThemeAdornmentNone; - - switch( aButtonValue ) { - case ButtonValue::On: aInfo.value = kThemeDisclosureDown;//expanded + switch (aButtonValue) + { + case ButtonValue::On: + aInfo.value = kThemeDisclosureDown; break; case ButtonValue::Off: - // FIXME: this should have drawn a theme compliant disclosure triangle - // (see above) - if( AllSettings::GetLayoutRTL() ) - { - aInfo.value = kThemeDisclosureLeft;//collapsed, RTL - } + if (AllSettings::GetLayoutRTL()) + aInfo.value = kThemeDisclosureLeft; break; - case ButtonValue::DontKnow: //what to do? + case ButtonValue::DontKnow: default: break; } - - HIThemeDrawButton( &rc, &aInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr ); + HIThemeDrawButton(&rc, &aInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); + bOK = true; } - bOK = true; - } - break; - - case ControlType::Progress: - case ControlType::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(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( AllSettings::GetLayoutRTL() ) - aTrackInfo.attributes |= kThemeTrackRightToLeft; - aTrackInfo.enableState = getTrackState( nState ); - // the intro bitmap never gets key anyway; we want to draw that enabled - if( nType == ControlType::IntroProgress ) - aTrackInfo.enableState = kThemeTrackActive; - aTrackInfo.filler1 = 0; - aTrackInfo.trackInfo.progress.phase = static_cast(CFAbsoluteTimeGetCurrent()*10.0); - - HIThemeDrawTrack( &aTrackInfo, nullptr, maContextHolder.get(), kHIThemeOrientationNormal ); - bOK = true; - } - break; - - case ControlType::Slider: - { - SliderValue const * pSLVal = static_cast(&aValue); - - HIThemeTrackDrawInfo aTrackDraw; - aTrackDraw.kind = kThemeSliderMedium; - if( nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea ) + break; + case ControlType::Progress: + case ControlType::IntroProgress: { - aTrackDraw.bounds = rc; - aTrackDraw.min = pSLVal->mnMin; - aTrackDraw.max = pSLVal->mnMax; - aTrackDraw.value = pSLVal->mnCur; - aTrackDraw.reserved = 0; - aTrackDraw.attributes = kThemeTrackShowThumb; - if( nPart == ControlPart::TrackHorzArea ) - aTrackDraw.attributes |= kThemeTrackHorizontal; - aTrackDraw.enableState = (nState & ControlState::ENABLED) - ? kThemeTrackActive : kThemeTrackInactive; - - SliderTrackInfo aSlideInfo; - aSlideInfo.thumbDir = kThemeThumbUpward; - aSlideInfo.pressState = 0; - aTrackDraw.trackInfo.slider = aSlideInfo; - - HIThemeDrawTrack( &aTrackDraw, nullptr, maContextHolder.get(), kHIThemeOrientationNormal ); + 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(rc.size.width); + aTrackInfo.value = nProgressWidth; + aTrackInfo.reserved = 0; + aTrackInfo.attributes = kThemeTrackHorizontal; + if (AllSettings::GetLayoutRTL()) + aTrackInfo.attributes |= kThemeTrackRightToLeft; + aTrackInfo.enableState = getTrackState(nState); + + // the intro bitmap never gets key anyway; we want to draw that enabled + + if (nType == ControlType::IntroProgress) + aTrackInfo.enableState = kThemeTrackActive; + aTrackInfo.filler1 = 0; + aTrackInfo.trackInfo.progress.phase = static_cast(CFAbsoluteTimeGetCurrent() * 10.0); + HIThemeDrawTrack(&aTrackInfo, nullptr, maContextHolder.get(), kHIThemeOrientationNormal); bOK = true; } - } - break; - - case ControlType::Scrollbar: - { - const ScrollbarValue* pScrollbarVal = (aValue.getType() == ControlType::Scrollbar) ? static_cast(&aValue) : nullptr; - - if( nPart == ControlPart::DrawBackgroundVert || - nPart == ControlPart::DrawBackgroundHorz ) + break; + case ControlType::Slider: { + const SliderValue *pSliderVal = static_cast(&aValue); HIThemeTrackDrawInfo aTrackDraw; - aTrackDraw.kind = kThemeMediumScrollBar; - // FIXME: the scrollbar length must be adjusted - if (nPart == ControlPart::DrawBackgroundVert) - 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 == ControlPart::DrawBackgroundHorz ) - aTrackDraw.attributes |= kThemeTrackHorizontal; - aTrackDraw.enableState = getTrackState( nState ); - - ScrollBarTrackInfo aScrollInfo; - aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize; - aScrollInfo.pressState = 0; - - if ( pScrollbarVal->mnButton1State & ControlState::ENABLED ) - { - if ( pScrollbarVal->mnButton1State & ControlState::PRESSED ) - aScrollInfo.pressState = kThemeTopOutsideArrowPressed; - } - - if ( pScrollbarVal->mnButton2State & ControlState::ENABLED ) + aTrackDraw.kind = kThemeSliderMedium; + if (nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea) { - if ( pScrollbarVal->mnButton2State & ControlState::PRESSED ) - aScrollInfo.pressState = kThemeBottomOutsideArrowPressed; + aTrackDraw.bounds = rc; + aTrackDraw.min = pSliderVal->mnMin; + aTrackDraw.max = pSliderVal->mnMax; + aTrackDraw.value = pSliderVal->mnCur; + aTrackDraw.reserved = 0; + aTrackDraw.attributes = kThemeTrackShowThumb; + if (nPart == ControlPart::TrackHorzArea) + aTrackDraw.attributes |= kThemeTrackHorizontal; + aTrackDraw.enableState = (nState & ControlState::ENABLED) ? kThemeTrackActive : kThemeTrackInactive; + SliderTrackInfo aSlideInfo; + aSlideInfo.thumbDir = kThemeThumbUpward; + aSlideInfo.pressState = 0; + aTrackDraw.trackInfo.slider = aSlideInfo; + HIThemeDrawTrack(&aTrackDraw, nullptr, maContextHolder.get(), kHIThemeOrientationNormal); + bOK = true; } - - if ( pScrollbarVal->mnThumbState & ControlState::ENABLED ) + } + break; + case ControlType::Scrollbar: + { + const ScrollbarValue *pScrollbarVal = (aValue.getType() == ControlType::Scrollbar) + ? static_cast(&aValue) : nullptr; + if (nPart == ControlPart::DrawBackgroundVert || nPart == ControlPart::DrawBackgroundHorz) { - if ( pScrollbarVal->mnThumbState & ControlState::PRESSED ) - aScrollInfo.pressState = kThemeThumbPressed; + HIThemeTrackDrawInfo aTrackDraw; + aTrackDraw.kind = kThemeMediumScrollBar; + 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 == ControlPart::DrawBackgroundHorz) + aTrackDraw.attributes |= kThemeTrackHorizontal; + aTrackDraw.enableState = getTrackState(nState); + ScrollBarTrackInfo aScrollInfo; + aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize; + aScrollInfo.pressState = 0; + if (pScrollbarVal->mnButton1State & ControlState::ENABLED) + if (pScrollbarVal->mnButton1State & ControlState::PRESSED) + aScrollInfo.pressState = kThemeTopOutsideArrowPressed; + if (pScrollbarVal->mnButton2State & ControlState::ENABLED ) + if (pScrollbarVal->mnButton2State & ControlState::PRESSED ) + aScrollInfo.pressState = kThemeBottomOutsideArrowPressed; + if ( pScrollbarVal->mnThumbState & ControlState::ENABLED) + if (pScrollbarVal->mnThumbState & ControlState::PRESSED) + aScrollInfo.pressState = kThemeThumbPressed; + aTrackDraw.trackInfo.scrollbar = aScrollInfo; + HIThemeDrawTrack(&aTrackDraw, nullptr, maContextHolder.get(), kHIThemeOrientationNormal); + bOK = true; } - - aTrackDraw.trackInfo.scrollbar = aScrollInfo; - - HIThemeDrawTrack( &aTrackDraw, nullptr, maContextHolder.get(), kHIThemeOrientationNormal ); - bOK = true; - } - } - break; - - case ControlType::TabPane: - { - 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, maContextHolder.get(), kHIThemeOrientationNormal); - - bOK = true; - } - break; - - case ControlType::TabItem: - { - HIThemeTabDrawInfo aTabItemDrawInfo; - aTabItemDrawInfo.version=1; - aTabItemDrawInfo.style=kThemeTabNonFront; - aTabItemDrawInfo.direction=kThemeTabNorth; - aTabItemDrawInfo.size=kHIThemeTabSizeNormal; - aTabItemDrawInfo.adornment=kHIThemeTabAdornmentTrailingSeparator; - //State - if(nState & ControlState::SELECTED) { - aTabItemDrawInfo.style=kThemeTabFront; } - if(nState & ControlState::FOCUSED) { - aTabItemDrawInfo.adornment|=kHIThemeTabAdornmentFocus; + break; + case ControlType::TabPane: + { + HIThemeTabPaneDrawInfo aTabPaneDrawInfo; + aTabPaneDrawInfo.version = 1; + aTabPaneDrawInfo.state = kThemeStateActive; + aTabPaneDrawInfo.direction = kThemeTabNorth; + aTabPaneDrawInfo.size = kHIThemeTabSizeNormal; + aTabPaneDrawInfo.kind = kHIThemeTabKindNormal; + + // border is outside the rect rc for Carbon but for VCL it should be inside + + rc.origin.x += 1; + rc.origin.y -= TAB_HEIGHT / 2; + rc.size.height += TAB_HEIGHT / 2; + rc.size.width -= 2; + HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal); + bOK = true; } - - //first, last or middle tab - aTabItemDrawInfo.position=kHIThemeTabPositionMiddle; - - TabitemValue const * pTabValue = static_cast(&aValue); - TabitemFlags nAlignment = pTabValue->mnAlignment; - //TabitemFlags::LeftAligned (and TabitemFlags::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 TabitemFlags::FirstInGroup (and TabitemFlags::LastInGroup) because when the - //line width is different from window width, there may not be TabitemFlags::RightAligned - if( ( (nAlignment & TabitemFlags::LeftAligned)&&(nAlignment & TabitemFlags::RightAligned) ) || - ( (nAlignment & TabitemFlags::FirstInGroup)&&(nAlignment & TabitemFlags::LastInGroup) ) - ) //tab alone - aTabItemDrawInfo.position=kHIThemeTabPositionOnly; - else if((nAlignment & TabitemFlags::LeftAligned)||(nAlignment & TabitemFlags::FirstInGroup)) - aTabItemDrawInfo.position=kHIThemeTabPositionFirst; - else if((nAlignment & TabitemFlags::RightAligned)||(nAlignment & TabitemFlags::LastInGroup)) - aTabItemDrawInfo.position=kHIThemeTabPositionLast; - - //support for RTL - //see issue 79748 - if( AllSettings::GetLayoutRTL() ) { - if( aTabItemDrawInfo.position == kHIThemeTabPositionFirst ) + break; + case ControlType::TabItem: + { + HIThemeTabDrawInfo aTabItemDrawInfo; + aTabItemDrawInfo.version = 1; + aTabItemDrawInfo.style = kThemeTabNonFront; + aTabItemDrawInfo.direction = kThemeTabNorth; + aTabItemDrawInfo.size = kHIThemeTabSizeNormal; + aTabItemDrawInfo.adornment = kHIThemeTabAdornmentTrailingSeparator; + if (nState & ControlState::SELECTED) + aTabItemDrawInfo.style = kThemeTabFront; + if(nState & ControlState::FOCUSED) + aTabItemDrawInfo.adornment |= kHIThemeTabAdornmentFocus; + + // first, last or middle tab + + aTabItemDrawInfo.position = kHIThemeTabPositionMiddle; + TabitemValue const * pTabValue = static_cast(&aValue); + TabitemFlags nAlignment = pTabValue->mnAlignment; + + // TabitemFlags::LeftAligned (and TabitemFlags::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 TabitemFlags::FirstInGroup (and TabitemFlags::LastInGroup) because when the + // line width is different from window width, there may not be TabitemFlags::RightAligned + + if (((nAlignment & TabitemFlags::LeftAligned) && (nAlignment & TabitemFlags::RightAligned)) + || ((nAlignment & TabitemFlags::FirstInGroup) && (nAlignment & TabitemFlags::LastInGroup))) + aTabItemDrawInfo.position = kHIThemeTabPositionOnly; + else if ((nAlignment & TabitemFlags::LeftAligned) || (nAlignment & TabitemFlags::FirstInGroup)) + aTabItemDrawInfo.position = kHIThemeTabPositionFirst; + else if ((nAlignment & TabitemFlags::RightAligned) || (nAlignment & TabitemFlags::LastInGroup)) + aTabItemDrawInfo.position = kHIThemeTabPositionLast; + + // support for RTL (see issue 79748) + + if (AllSettings::GetLayoutRTL()) { + if (aTabItemDrawInfo.position == kHIThemeTabPositionFirst) aTabItemDrawInfo.position = kHIThemeTabPositionLast; - else if( aTabItemDrawInfo.position == kHIThemeTabPositionLast ) + else if (aTabItemDrawInfo.position == kHIThemeTabPositionLast) aTabItemDrawInfo.position = kHIThemeTabPositionFirst; + } + rc.size.width += VCL_TAB_TEXT_SEPARATOR; + rc.origin.x -= 1; + HIThemeDrawTab(&rc, &aTabItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); + bOK=true; } - - rc.size.width+=2;//because VCL has 2 empty pixels between 2 tabs - rc.origin.x-=1; - - HIThemeDrawTab(&rc, &aTabItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, &rc ); - - bOK=true; - } - break; - - case ControlType::Listbox: - switch( nPart) - { - case ControlPart::Entire: - case ControlPart::ButtonDown: + break; + case ControlType::Editbox: + case ControlType::MultilineEditbox: { - HIThemeButtonDrawInfo aListInfo; - aListInfo.version = 0; - aListInfo.kind = kThemePopupButton; - aListInfo.state = getState( nState );//kThemeStateInactive -> greyed - aListInfo.value = kThemeButtonOn; + HIThemeFrameDrawInfo aTextDrawInfo; + aTextDrawInfo.version = 0; + aTextDrawInfo.kind = kHIThemeFrameTextFieldSquare; + aTextDrawInfo.state = getState(nState); + aTextDrawInfo.isFocused = false; + rc.size.width += 2 * EDITBOX_INSET_MARGIN; + if (nType == ControlType::Editbox) + rc.size.height = EDITBOX_HEIGHT; + else + rc.size.height += 2 * (EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN); + rc.origin.x -= EDITBOX_INSET_MARGIN; + rc.origin.y -= EDITBOX_INSET_MARGIN; - aListInfo.adornment = kThemeAdornmentDefault; - if( nState & ControlState::FOCUSED ) - aListInfo.adornment |= kThemeAdornmentFocus; + // fill a white background, because HIThemeDrawFrame only draws the border - HIThemeDrawButton(&rc, &aListInfo, maContextHolder.get(), kHIThemeOrientationNormal,&rc); + CGContextFillRect(maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height)); + HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal); + if (nState & ControlState::FOCUSED) + HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal); bOK = true; - break; } - case ControlPart::ListboxWindow: + break; + case ControlType::Combobox: + if (nPart == ControlPart::HasBackgroundTexture || nPart == ControlPart::Entire) { - 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 a macOS theme has no 3D border - rc.size.height+=1; - HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal); - - if(nState & ControlState::FOCUSED) HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal); - - bOK=true; - break; + HIThemeButtonDrawInfo aComboInfo; + aComboInfo.version = 0; + aComboInfo.kind = kThemeComboBox; + aComboInfo.state = getState(nState); + aComboInfo.value = kThemeButtonOn; + aComboInfo.adornment = kThemeAdornmentNone; + if (nState & ControlState::FOCUSED) + aComboInfo.adornment |= kThemeAdornmentFocus; + rc.size.width -= 2 * FOCUS_RING_WIDTH; + rc.size.height = COMBOBOX_HEIGHT; + rc.origin.x += FOCUS_RING_WIDTH; + rc.origin.y += FOCUS_RING_WIDTH; + HIThemeDrawButton(&rc, &aComboInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); + bOK = true; + } + break; + case ControlType::Listbox: + switch (nPart) + { + case ControlPart::Entire: + case ControlPart::ButtonDown: + HIThemeButtonDrawInfo aListInfo; + aListInfo.version = 0; + aListInfo.kind = kThemePopupButton; + aListInfo.state = getState(nState); + aListInfo.value = kThemeButtonOn; + aListInfo.adornment = kThemeAdornmentDefault; + if (nState & ControlState::FOCUSED) + aListInfo.adornment |= kThemeAdornmentFocus; + rc.size.width -= 2 * FOCUS_RING_WIDTH; + rc.size.height = LISTBOX_HEIGHT; + rc.origin.x += FOCUS_RING_WIDTH; + rc.origin.y += FOCUS_RING_WIDTH; + HIThemeDrawButton(&rc, &aListInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); + bOK = true; + break; + case ControlPart::ListboxWindow: + HIThemeFrameDrawInfo aTextDrawInfo; + aTextDrawInfo.version = 0; + aTextDrawInfo.kind = kHIThemeFrameTextFieldSquare; + aTextDrawInfo.state = getState(nState); + aTextDrawInfo.isFocused = false; + rc.size.width -= 2 * FOCUS_RING_WIDTH; + rc.size.height -= 2 * FOCUS_RING_WIDTH; + rc.origin.x += FOCUS_RING_WIDTH; + rc.origin.y += FOCUS_RING_WIDTH; + HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal); + if (nState & ControlState::FOCUSED) + HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal); + bOK = true; + break; + default: + break; } - default: break; - } - break; - - case ControlType::Editbox: - case ControlType::MultilineEditbox: - { - 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 a macOS theme has no 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 (maContextHolder.get(), 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, maContextHolder.get(), kHIThemeOrientationNormal); - - if(nState & ControlState::FOCUSED) HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal); - - bOK=true; - } - break; - - case ControlType::Spinbox: - { - if(nPart == ControlPart::Entire) + break; + case ControlType::Spinbox: + if (nPart == ControlPart::Entire) { - //text field: + + // 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; + aTextDrawInfo.version = 0; + aTextDrawInfo.kind = kHIThemeFrameTextFieldSquare; + aTextDrawInfo.state = getState(nState); + aTextDrawInfo.isFocused = false; + rc.size.width -= SPIN_BUTTON_WIDTH + 4 * FOCUS_RING_WIDTH; + rc.size.height = EDITBOX_HEIGHT; rc.origin.x += FOCUS_RING_WIDTH; rc.origin.y += FOCUS_RING_WIDTH; - //CGContextSetFillColorWithColor - CGContextFillRect (maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height)); - //fill a white background, because drawFrame only draws the border + // fill a white background, because HIThemeDrawFrame only draws the border + CGContextFillRect(maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height)); HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal); + if (nState & ControlState::FOCUSED) + HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal); - if(nState & ControlState::FOCUSED) HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal); + // buttons - //buttons: - const SpinbuttonValue* pSpinButtonVal = (aValue.getType() == ControlType::SpinButtons) ? static_cast(&aValue) : nullptr; - ControlState nUpperState = ControlState::ENABLED;//state of the upper button - ControlState nLowerState = ControlState::ENABLED;//and of the lower button - if(pSpinButtonVal) {//pSpinButtonVal is sometimes null + const SpinbuttonValue *pSpinButtonVal = (aValue.getType() == ControlType::SpinButtons) + ? static_cast (&aValue) : nullptr; + ControlState nUpperState = ControlState::ENABLED; + ControlState nLowerState = ControlState::ENABLED; + if (pSpinButtonVal) + { nUpperState = pSpinButtonVal->mnUpperState; nLowerState = pSpinButtonVal->mnLowerState; - HIThemeButtonDrawInfo aSpinInfo; aSpinInfo.kind = kThemeIncDecButton; aSpinInfo.state = kThemeStateActive; - if(nUpperState & ControlState::PRESSED) + if (nUpperState & ControlState::PRESSED) aSpinInfo.state = kThemeStatePressedUp; - else if(nLowerState & ControlState::PRESSED) + else if (nLowerState & ControlState::PRESSED) aSpinInfo.state = kThemeStatePressedDown; - else if((nUpperState & ~ControlState::ENABLED)||(nLowerState & ~ControlState::ENABLED)) + else if (nUpperState & ~ControlState::ENABLED || nLowerState & ~ControlState::ENABLED) aSpinInfo.state = kThemeStateInactive; - else if((nUpperState & ControlState::ROLLOVER)||(nLowerState & ControlState::ROLLOVER)) + else if (nUpperState & ControlState::ROLLOVER || nLowerState & ControlState::ROLLOVER) aSpinInfo.state = kThemeStateRollover; - - tools::Rectangle aSpinRect( pSpinButtonVal->maUpperRect ); - aSpinRect.Union( pSpinButtonVal->maLowerRect ); - HIRect buttonRc = ImplGetHIRectFromRectangle(aSpinRect); - - // FIXME: without this fuzz factor there is some unwanted clipping - if( AllSettings::GetLayoutRTL() ) - buttonRc.origin.x -= FOCUS_RING_WIDTH - CLIP_FUZZ; - else - buttonRc.origin.x += FOCUS_RING_WIDTH + CLIP_FUZZ; - - switch( aValue.getTristateVal() ) + switch (aValue.getTristateVal()) { - case ButtonValue::On: aSpinInfo.value = kThemeButtonOn; - break; - case ButtonValue::Off: aSpinInfo.value = kThemeButtonOff; - break; + 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; + default: + aSpinInfo.value = kThemeButtonMixed; + break; } - - aSpinInfo.adornment = ( (nUpperState & ControlState::DEFAULT) || - (nLowerState & ControlState::DEFAULT) ) ? - kThemeAdornmentDefault : - kThemeAdornmentNone; - if( (nUpperState & ControlState::FOCUSED) || (nLowerState & ControlState::FOCUSED)) + aSpinInfo.adornment = (nUpperState & ControlState::DEFAULT || nLowerState & ControlState::DEFAULT) + ? kThemeAdornmentDefault : kThemeAdornmentNone; + if (nUpperState & ControlState::FOCUSED || nLowerState & ControlState::FOCUSED) aSpinInfo.adornment |= kThemeAdornmentFocus; - - HIThemeDrawButton( &buttonRc, &aSpinInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr ); + rc.origin.x += rc.size.width + 2 * FOCUS_RING_WIDTH; + rc.size.width = SPIN_BUTTON_WIDTH; + rc.size.height = SPIN_LOWER_BUTTON_HEIGHT + SPIN_LOWER_BUTTON_HEIGHT; + HIThemeDrawButton(&rc, &aSpinInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); } - - bOK=true; + bOK = true; } - - } - break; - - case ControlType::Frame: - { - DrawFrameFlags nStyle = static_cast(aValue.getNumericVal()); - if( nPart == ControlPart::Border ) { - if(!( nStyle & DrawFrameFlags::Menu ) && !(nStyle & DrawFrameFlags::WindowBorder) ) + break; + case ControlType::Frame: + { + DrawFrameFlags nStyle = static_cast(aValue.getNumericVal()); + if (nPart == ControlPart::Border) { - // #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 ) + if (!(nStyle & DrawFrameFlags::Menu) && !(nStyle & DrawFrameFlags::WindowBorder)) { - CGMutablePathRef rPath = CGPathCreateMutable(); - CGPathAddRect( rPath, nullptr, CGRectMake( 0, 0, mpFrame->maGeometry.nWidth-1, mpFrame->maGeometry.nHeight-1 ) ); - - CGContextBeginPath( maContextHolder.get() ); - CGContextAddPath( maContextHolder.get(), rPath ); - CGContextClip( maContextHolder.get() ); - CGPathRelease( rPath ); - } - - HIThemeFrameDrawInfo aTextDrawInfo; - aTextDrawInfo.version=0; - aTextDrawInfo.kind=kHIThemeFrameListBox; - aTextDrawInfo.state=kThemeStateActive; - aTextDrawInfo.isFocused=false; - HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal); + // 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 (see issue 84756) - bOK=true; + if (rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight - 3) + { + CGMutablePathRef rPath = CGPathCreateMutable(); + CGPathAddRect(rPath, nullptr, + CGRectMake(0, 0, mpFrame->maGeometry.nWidth - 1, mpFrame->maGeometry.nHeight - 1)); + CGContextBeginPath(maContextHolder.get()); + CGContextAddPath(maContextHolder.get(), rPath); + CGContextClip(maContextHolder.get()); + CGPathRelease(rPath); + } + HIThemeFrameDrawInfo aTextDrawInfo; + aTextDrawInfo.version = 0; + aTextDrawInfo.kind = kHIThemeFrameListBox; + aTextDrawInfo.state = kThemeStateActive; + aTextDrawInfo.isFocused = false; + HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal); + bOK = true; + } } } - } - break; - - case ControlType::ListNet: - { - //do nothing as there isn't net for listviews on macos - bOK=true; - } - break; - default: break; - } + break; + case ControlType::ListNet: - maContextHolder.restoreState(); + // do nothing as there isn't net for listviews on macOS - /* #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 == ControlType::WindowBackground ) - { - CGRect aRect = { { 0, 0 }, { 0, 0 } }; - if( mxClipPath ) - aRect = CGPathGetBoundingBox( mxClipPath ); - if( aRect.size.width != 0 && aRect.size.height != 0 ) - buttonRect.Intersection( tools::Rectangle( Point( static_cast(aRect.origin.x), - static_cast(aRect.origin.y) ), - Size( static_cast(aRect.size.width), - static_cast(aRect.size.height) ) ) ); + bOK = true; + break; + default: + break; } + maContextHolder.restoreState(); - RefreshRect( buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight() ); + // 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. Background is always drawn as a whole since we don't know anything about its possible + // contents (see issue i90291). + if (nType == ControlType::WindowBackground) + { + CGRect aRect = {{0, 0}, {0, 0}}; + if (mxClipPath) + aRect = CGPathGetBoundingBox(mxClipPath); + if (aRect.size.width != 0 && aRect.size.height != 0) + buttonRect.Intersection(tools::Rectangle(Point(static_cast(aRect.origin.x), + static_cast(aRect.origin.y)), + Size(static_cast(aRect.size.width), + static_cast(aRect.size.height)))); + } + RefreshRect(buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight()); return bOK; } -bool AquaSalGraphics::getNativeControlRegion( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, ControlState /*nState*/, - const ImplControlValue& aValue, const OUString&, - tools::Rectangle &rNativeBoundingRegion, tools::Rectangle &rNativeContentRegion ) - +bool AquaSalGraphics::getNativeControlRegion(ControlType nType, + ControlPart nPart, + const tools::Rectangle &rControlRegion, + ControlState, + const ImplControlValue &aValue, + const OUString &, + tools::Rectangle &rNativeBoundingRegion, + tools::Rectangle &rNativeContentRegion) { bool toReturn = false; - - tools::Rectangle aCtrlBoundRect( rControlRegion ); + tools::Rectangle aCtrlBoundRect(rControlRegion); short x = aCtrlBoundRect.Left(); short y = aCtrlBoundRect.Top(); short w, h; - - sal_uInt8 nBorderCleanup = 0; - switch (nType) { - case ControlType::Slider: - { - if( nPart == ControlPart::ThumbHorz ) - { - w = 19; // taken from HIG - h = aCtrlBoundRect.GetHeight(); - rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) ); - toReturn = true; - } - else if( nPart == ControlPart::ThumbVert ) - { - w = aCtrlBoundRect.GetWidth(); - h = 18; // taken from HIG - rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) ); - toReturn = true; - } - } - break; - - case ControlType::Scrollbar: - { - tools::Rectangle aRect; - if( AquaGetScrollRect( /* m_nScreen */ nPart, aCtrlBoundRect, aRect ) ) - { - toReturn = true; - rNativeBoundingRegion = aRect; - rNativeContentRegion = aRect; - } - } - break; - case ControlType::Pushbutton: case ControlType::Radiobutton: case ControlType::Checkbox: { - if ( nType == ControlType::Pushbutton ) + if (nType == ControlType::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; - + w = RADIO_BUTTON_SMALL_SIZE + 2 * FOCUS_RING_WIDTH + RADIO_BUTTON_TEXT_SEPARATOR; + h = RADIO_BUTTON_SMALL_SIZE + 2 * FOCUS_RING_WIDTH; } - - rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h + nBorderCleanup) ); - rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) ); - + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); toReturn = true; } break; case ControlType::Progress: { - tools::Rectangle aRect( aCtrlBoundRect ); - if( aRect.GetHeight() < 16 ) - aRect.SetBottom( aRect.Top() + 9 ); // values taken from HIG for medium progress + tools::Rectangle aRect(aCtrlBoundRect); + if (aRect.GetHeight() < LARGE_PROGRESS_INDICATOR_HEIGHT) + aRect.SetBottom(aRect.Top() + MEDIUM_PROGRESS_INDICATOR_HEIGHT - 1); else - aRect.SetBottom( aRect.Top() + 15 ); // values taken from HIG for large progress + aRect.SetBottom(aRect.Top() + LARGE_PROGRESS_INDICATOR_HEIGHT - 1); rNativeBoundingRegion = aRect; rNativeContentRegion = aRect; toReturn = true; } break; - case ControlType::IntroProgress: { - tools::Rectangle aRect( aCtrlBoundRect ); - aRect.SetBottom( aRect.Top() + INTRO_PROGRESS_HEIGHT ); // values taken from HIG for medium progress + tools::Rectangle aRect(aCtrlBoundRect); + aRect.SetBottom(aRect.Top() + MEDIUM_PROGRESS_INDICATOR_HEIGHT - 1); rNativeBoundingRegion = aRect; rNativeContentRegion = aRect; toReturn = true; } break; - - case ControlType::TabItem: - - w = aCtrlBoundRect.GetWidth() + 2*TAB_TEXT_OFFSET - 2*VCL_TAB_TEXT_OFFSET; - h = TAB_HEIGHT_NORMAL+2; - - rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) ); - rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) ); - - toReturn = true; - - break; - - case ControlType::Editbox: + case ControlType::Slider: + if (nPart == ControlPart::ThumbHorz) + { + w = SLIDER_WIDTH; + h = aCtrlBoundRect.GetHeight(); + rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::ThumbVert) { 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 = tools::Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*(FOCUS_RING_WIDTH+1), h-2*(FOCUS_RING_WIDTH+1) ) ); - rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) ); - + h = SLIDER_HEIGHT; + rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); toReturn = true; } break; - case ControlType::Listbox: - case ControlType::Combobox: + case ControlType::Scrollbar: { - if( nPart == ControlPart::Entire ) - { - w = aCtrlBoundRect.GetWidth(); - h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height - - rNativeContentRegion = tools::Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*FOCUS_RING_WIDTH, h ) ); - rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) ); - - toReturn = true; - } - else if( nPart == ControlPart::ButtonDown ) - { - 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 = tools::Rectangle( Point( x, y ), Size( w, h ) ); - rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) ); - - toReturn = true; - } - else if( nPart == ControlPart::SubEdit ) + tools::Rectangle aRect; + if (AquaGetScrollRect(nPart, aCtrlBoundRect, aRect)) { - 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 == ControlType::Listbox ) - w -= 9; // HIG specifies 9 units distance between dropdown button area and content - h -= 4; // don't draw into lower border - - rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) ); - rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) ); - toReturn = true; + rNativeBoundingRegion = aRect; + rNativeContentRegion = aRect; } } break; + case ControlType::TabItem: + { + w = aCtrlBoundRect.GetWidth() + 2 * TAB_TEXT_MARGIN - 2 * VCL_TAB_TEXT_SEPARATOR; + h = TAB_HEIGHT + 2; + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + break; + case ControlType::Editbox: + { + w = aCtrlBoundRect.GetWidth(); + h = EDITBOX_HEIGHT + 2 * FOCUS_RING_WIDTH; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + w -= 2 * (FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN); + h -= 2 * (FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN); + x += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN; + y += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN; + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + break; + case ControlType::Combobox: + if (nPart == ControlPart::Entire) + { + w = aCtrlBoundRect.GetWidth(); + h = COMBOBOX_HEIGHT + 2 * FOCUS_RING_WIDTH; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::ButtonDown) + { + w = COMBOBOX_BUTTON_WIDTH + FOCUS_RING_WIDTH; + h = COMBOBOX_HEIGHT + 2 * FOCUS_RING_WIDTH; + x += aCtrlBoundRect.GetWidth() - w; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::SubEdit) + { + w = aCtrlBoundRect.GetWidth() - 2 * FOCUS_RING_WIDTH - COMBOBOX_BUTTON_WIDTH - COMBOBOX_BORDER_WIDTH + - 2 * COMBOBOX_TEXT_MARGIN; + h = COMBOBOX_HEIGHT - 2 * COMBOBOX_BORDER_WIDTH; + x += FOCUS_RING_WIDTH + COMBOBOX_BORDER_WIDTH + COMBOBOX_TEXT_MARGIN; + y += FOCUS_RING_WIDTH + COMBOBOX_BORDER_WIDTH; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + break; + case ControlType::Listbox: + if (nPart == ControlPart::Entire) + { + w = aCtrlBoundRect.GetWidth(); + h = LISTBOX_HEIGHT + 2 * FOCUS_RING_WIDTH; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::ButtonDown) + { + w = LISTBOX_BUTTON_WIDTH + FOCUS_RING_WIDTH; + h = LISTBOX_HEIGHT + 2 * FOCUS_RING_WIDTH; + x += aCtrlBoundRect.GetWidth() - w; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::SubEdit) + { + w = aCtrlBoundRect.GetWidth() - 2 * FOCUS_RING_WIDTH - LISTBOX_BUTTON_WIDTH - LISTBOX_BORDER_WIDTH + - 2 * LISTBOX_TEXT_MARGIN; + h = LISTBOX_HEIGHT - 2 * LISTBOX_BORDER_WIDTH; + x += FOCUS_RING_WIDTH + LISTBOX_BORDER_WIDTH + LISTBOX_TEXT_MARGIN; + y += FOCUS_RING_WIDTH + LISTBOX_BORDER_WIDTH; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + break; case ControlType::Spinbox: - if( nPart == ControlPart::Entire ) { - 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 = tools::Rectangle( Point( x+FOCUS_RING_WIDTH, y ), Size( w-2*FOCUS_RING_WIDTH, h ) ); - rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) ); - - toReturn = true; - } - else if( nPart == ControlPart::SubEdit ) { - 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 lower border - - rNativeContentRegion = tools::Rectangle( Point( x + FOCUS_RING_WIDTH, y + FOCUS_RING_WIDTH ), Size( w - 2* FOCUS_RING_WIDTH, h ) ); - rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) ); - - toReturn = true; - } - else if( nPart == ControlPart::ButtonUp ) { - //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 = tools::Rectangle( Point( x, y ), Size( w, h ) ); - rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) ); - - toReturn = true; - } - else if( nPart == ControlPart::ButtonDown ) { - 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 = tools::Rectangle( Point( x, y ), Size( w, h ) ); - rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) ); - - toReturn = true; - } + if (nPart == ControlPart::Entire) + { + w = aCtrlBoundRect.GetWidth(); + h = EDITBOX_HEIGHT + 2 * FOCUS_RING_WIDTH; + x += SPINBOX_OFFSET; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::SubEdit) + { + w = aCtrlBoundRect.GetWidth() - 4 * FOCUS_RING_WIDTH - SPIN_BUTTON_WIDTH - 2 * EDITBOX_BORDER_WIDTH + - 2 * EDITBOX_INSET_MARGIN; + h = EDITBOX_HEIGHT - 2 * (EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN); + x += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN + SPINBOX_OFFSET; + y += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::ButtonUp) + { + w = SPIN_BUTTON_WIDTH + 2 * FOCUS_RING_WIDTH; + h = SPIN_UPPER_BUTTON_HEIGHT + FOCUS_RING_WIDTH; + x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - 2 * FOCUS_RING_WIDTH + SPINBOX_OFFSET; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::ButtonDown) + { + w = SPIN_BUTTON_WIDTH + 2 * FOCUS_RING_WIDTH; + h = SPIN_LOWER_BUTTON_HEIGHT + FOCUS_RING_WIDTH; + x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - 2 * FOCUS_RING_WIDTH + SPINBOX_OFFSET; + y += FOCUS_RING_WIDTH + SPIN_UPPER_BUTTON_HEIGHT; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } break; case ControlType::Frame: { DrawFrameStyle nStyle = static_cast(aValue.getNumericVal() & 0x000f); DrawFrameFlags nFlags = static_cast(aValue.getNumericVal() & 0xfff0); - if( ( nPart == ControlPart::Border ) && - !( nFlags & (DrawFrameFlags::Menu | DrawFrameFlags::WindowBorder | DrawFrameFlags::BorderWindowBorder) ) ) + if (nPart == ControlPart::Border + && !(nFlags & (DrawFrameFlags::Menu | DrawFrameFlags::WindowBorder | DrawFrameFlags::BorderWindowBorder))) { tools::Rectangle aRect(aCtrlBoundRect); - if( nStyle == DrawFrameStyle::DoubleIn ) + if (nStyle == DrawFrameStyle::DoubleIn) { aRect.AdjustLeft(1); aRect.AdjustTop(1); - //rRect.Right() -= 1; - //rRect.Bottom() -= 1; + // rRect.Right() -= 1; + // rRect.Bottom() -= 1; } else { @@ -1258,34 +1109,26 @@ bool AquaSalGraphics::getNativeControlRegion( ControlType nType, ControlPart nPa aRect.AdjustRight(-1); aRect.AdjustBottom(-1); } - rNativeContentRegion = aRect; rNativeBoundingRegion = aRect; - toReturn = true; } } break; - case ControlType::Menubar: case ControlType::MenuPopup: + if (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark) { - if(( nPart == ControlPart::MenuItemCheckMark )||( nPart == ControlPart::MenuItemRadioMark )) { - - w=10; - h=10;//dimensions of the mark (10px font) - - rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) ); - rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) ); - - toReturn = true; - } + w=10; + h=10; + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; } break; - default: break; - + default: + break; } - return toReturn; } -- cgit