Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / osx / salnativewidgets.cxx
blob7c91d058c29208b6c74d0b820a712bdea65f80de
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <vcl/salnativewidgets.hxx>
23 #include <vcl/decoview.hxx>
24 #include <vcl/svapp.hxx>
25 #include <vcl/timer.hxx>
26 #include <vcl/settings.hxx>
28 #include "quartz/salgdi.h"
29 #include "osx/salnativewidgets.h"
30 #include "osx/saldata.hxx"
31 #include "osx/salframe.h"
33 #include "premac.h"
34 #include <Carbon/Carbon.h>
35 #include "postmac.h"
37 #include <cuidraw.hxx>
39 #if !HAVE_FEATURE_MACOSX_SANDBOX
41 @interface NSWindow(CoreUIRendererPrivate)
42 + (CUIRendererRef)coreUIRenderer;
43 @end
45 #endif
47 class AquaBlinker : public Timer
49 AquaSalFrame* mpFrame;
50 tools::Rectangle maInvalidateRect;
52 AquaBlinker( AquaSalFrame* pFrame, const tools::Rectangle& rRect )
53 : mpFrame( pFrame ), maInvalidateRect( rRect )
55 mpFrame->maBlinkers.push_back( this );
58 public:
60 static void Blink( AquaSalFrame*, const tools::Rectangle&, int nTimeout = 80 );
62 virtual void Invoke() override
64 Stop();
65 if( AquaSalFrame::isAlive( mpFrame ) && mpFrame->mbShown )
67 mpFrame->maBlinkers.remove( this );
68 mpFrame->SendPaintEvent( &maInvalidateRect );
70 delete this;
74 void AquaBlinker::Blink( AquaSalFrame* pFrame, const tools::Rectangle& rRect, int nTimeout )
76 // prevent repeated paints from triggering themselves all the time
77 for( std::list< AquaBlinker* >::const_iterator it = pFrame->maBlinkers.begin();
78 it != pFrame->maBlinkers.end(); ++it )
80 if( (*it)->maInvalidateRect == rRect )
81 return;
83 AquaBlinker* pNew = new AquaBlinker( pFrame, rRect );
84 pNew->SetTimeout( nTimeout );
85 pNew->Start();
88 // Helper returns an HIRect
90 static HIRect ImplGetHIRectFromRectangle(tools::Rectangle aRect)
92 HIRect aHIRect;
93 aHIRect.origin.x = static_cast<float>(aRect.Left());
94 aHIRect.origin.y = static_cast<float>(aRect.Top());
95 aHIRect.size.width = static_cast<float>(aRect.GetWidth());
96 aHIRect.size.height = static_cast<float>(aRect.GetHeight());
97 return aHIRect;
100 static ThemeButtonValue ImplGetButtonValue( ButtonValue aButtonValue )
102 switch( aButtonValue )
104 case ButtonValue::On:
105 return kThemeButtonOn;
106 break;
108 case ButtonValue::Off:
109 return kThemeButtonOff;
110 break;
112 case ButtonValue::Mixed:
113 case ButtonValue::DontKnow:
114 default:
115 return kThemeButtonMixed;
116 break;
120 static bool AquaGetScrollRect( /* TODO: int nScreen, */ ControlPart nPart,
121 const tools::Rectangle& rControlRect, tools::Rectangle& rResultRect )
123 bool bRetVal = true;
124 rResultRect = rControlRect;
126 switch( nPart )
128 case ControlPart::ButtonUp:
129 rResultRect.Bottom() = rResultRect.Top();
130 break;
132 case ControlPart::ButtonDown:
133 rResultRect.Top() = rResultRect.Bottom();
134 break;
136 case ControlPart::ButtonLeft:
137 rResultRect.Right() = rResultRect.Left();
138 break;
140 case ControlPart::ButtonRight:
141 rResultRect.Left() = rResultRect.Right();
142 break;
144 case ControlPart::TrackHorzArea:
145 case ControlPart::TrackVertArea:
146 case ControlPart::ThumbHorz:
147 case ControlPart::ThumbVert:
148 case ControlPart::TrackHorzLeft:
149 case ControlPart::TrackHorzRight:
150 case ControlPart::TrackVertUpper:
151 case ControlPart::TrackVertLower:
152 break;
153 default:
154 bRetVal = false;
157 return bRetVal;
160 bool AquaSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
162 bool bOk = false;
164 // Native controls are now defaults
165 // If you want to disable experimental native controls code,
166 // just set the environment variable SAL_NO_NWF to something
167 // and vcl controls will be used as default again.
169 switch( nType )
171 case ControlType::Pushbutton:
172 case ControlType::Radiobutton:
173 case ControlType::Checkbox:
174 case ControlType::ListNode:
175 if( nPart == ControlPart::Entire )
176 return true;
177 break;
179 case ControlType::Scrollbar:
180 if( nPart == ControlPart::DrawBackgroundHorz ||
181 nPart == ControlPart::DrawBackgroundVert ||
182 nPart == ControlPart::Entire ||
183 nPart == ControlPart::HasThreeButtons )
184 return true;
185 break;
187 case ControlType::Slider:
188 if( nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea )
189 return true;
190 break;
192 case ControlType::Editbox:
193 if( nPart == ControlPart::Entire ||
194 nPart == ControlPart::HasBackgroundTexture )
195 return true;
196 break;
198 case ControlType::MultilineEditbox:
199 if( nPart == ControlPart::Entire ||
200 nPart == ControlPart::HasBackgroundTexture )
201 return true;
202 break;
204 case ControlType::Spinbox:
205 if( nPart == ControlPart::Entire ||
206 nPart == ControlPart::AllButtons ||
207 nPart == ControlPart::HasBackgroundTexture )
208 return true;
209 break;
211 case ControlType::SpinButtons:
212 return false;
213 break;
215 case ControlType::Combobox:
216 if( nPart == ControlPart::Entire ||
217 nPart == ControlPart::HasBackgroundTexture )
218 return true;
219 break;
221 case ControlType::Listbox:
222 if( nPart == ControlPart::Entire ||
223 nPart == ControlPart::ListboxWindow ||
224 nPart == ControlPart::HasBackgroundTexture ||
225 nPart == ControlPart::SubEdit
227 return true;
228 break;
230 case ControlType::TabItem:
231 case ControlType::TabPane:
232 case ControlType::TabBody: // see vcl/source/window/tabpage.cxx
233 if( nPart == ControlPart::Entire ||
234 nPart == ControlPart::TabsDrawRtl ||
235 nPart == ControlPart::HasBackgroundTexture )
236 return true;
237 break;
239 // when ControlPart::Button is used, toolbar icons are not highlighted when mouse rolls over.
240 // More Aqua compliant
241 case ControlType::Toolbar:
242 if( nPart == ControlPart::Entire ||
243 nPart == ControlPart::DrawBackgroundHorz ||
244 nPart == ControlPart::DrawBackgroundVert)
245 return true;
246 break;
248 case ControlType::WindowBackground:
249 if ( nPart == ControlPart::BackgroundWindow ||
250 nPart == ControlPart::BackgroundDialog )
251 return true;
252 break;
254 case ControlType::Menubar:
255 if( nPart == ControlPart::Entire )
256 return true;
257 break;
259 case ControlType::Tooltip: // ** TO DO
260 break;
262 case ControlType::MenuPopup:
263 if( nPart == ControlPart::Entire ||
264 nPart == ControlPart::MenuItem ||
265 nPart == ControlPart::MenuItemCheckMark ||
266 nPart == ControlPart::MenuItemRadioMark)
267 return true;
268 break;
269 case ControlType::Progress:
270 case ControlType::IntroProgress:
271 if( nPart == ControlPart::Entire )
272 return true;
273 break;
274 case ControlType::Frame:
275 if( nPart == ControlPart::Border )
276 return true;
277 break;
278 case ControlType::ListNet:
279 if( nPart == ControlPart::Entire )
280 return true;
281 break;
282 default: break;
285 return bOk;
288 bool AquaSalGraphics::hitTestNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion,
289 const Point& rPos, bool& rIsInside )
291 if ( nType == ControlType::Scrollbar )
293 tools::Rectangle aRect;
294 bool bValid = AquaGetScrollRect( /* TODO: m_nScreen */ nPart, rControlRegion, aRect );
295 rIsInside = bValid && aRect.IsInside( rPos );
296 return bValid;
297 } // ControlType::Scrollbar
299 return false;
303 kThemeStateInactive = 0,
304 kThemeStateActive = 1,
305 kThemeStatePressed = 2,
306 kThemeStateRollover = 6,
307 kThemeStateUnavailable = 7,
308 kThemeStateUnavailableInactive = 8
309 kThemeStatePressedUp = 2,
310 kThemeStatePressedDown = 3
312 UInt32 AquaSalGraphics::getState( ControlState nState )
314 const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
315 if( !(nState & ControlState::ENABLED) || ! bDrawActive )
317 return kThemeStateInactive;
320 if( nState & ControlState::PRESSED )
321 return kThemeStatePressed;
323 return kThemeStateActive;
326 UInt32 AquaSalGraphics::getTrackState( ControlState nState )
328 const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
329 if( ! (nState & ControlState::ENABLED) || ! bDrawActive )
330 return kThemeTrackInactive;
332 return kThemeTrackActive;
335 bool AquaSalGraphics::drawNativeControl(ControlType nType,
336 ControlPart nPart,
337 const tools::Rectangle& rControlRegion,
338 ControlState nState,
339 const ImplControlValue& aValue,
340 const OUString& )
342 bool bOK = false;
344 if( ! CheckContext() )
345 return false;
347 CGContextSaveGState( mrContext );
349 tools::Rectangle buttonRect = rControlRegion;
350 HIRect rc = ImplGetHIRectFromRectangle(buttonRect);
352 switch( nType )
355 case ControlType::Combobox:
356 if ( nPart == ControlPart::HasBackgroundTexture ||
357 nPart == ControlPart::Entire )
359 HIThemeButtonDrawInfo aComboInfo;
360 aComboInfo.version = 0;
361 aComboInfo.kind = kThemeComboBox;
362 aComboInfo.state = getState( nState );
363 aComboInfo.value = kThemeButtonOn;
364 aComboInfo.adornment = kThemeAdornmentNone;
366 if( nState & ControlState::FOCUSED )
367 aComboInfo.adornment |= kThemeAdornmentFocus;
369 HIThemeDrawButton(&rc, &aComboInfo, mrContext, kHIThemeOrientationNormal,&rc);
370 bOK = true;
372 break;
374 case ControlType::Toolbar:
376 #if HAVE_FEATURE_MACOSX_SANDBOX
377 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
378 aMenuItemDrawInfo.version = 0;
379 aMenuItemDrawInfo.state = kThemeMenuActive;
380 aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
381 HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,NULL);
382 #else
383 if (rControlRegion.Top() == 0 && nPart == ControlPart::DrawBackgroundHorz)
385 const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
386 CGFloat unifiedHeight = rControlRegion.GetHeight();
387 CGRect drawRect = CGRectMake(rControlRegion.Left(), rControlRegion.Top(), rControlRegion.GetWidth(), rControlRegion.GetHeight());
388 CUIDraw([NSWindow coreUIRenderer], drawRect, mrContext,
389 reinterpret_cast<CFDictionaryRef>([NSDictionary dictionaryWithObjectsAndKeys:
390 @"kCUIWidgetWindowFrame", @"widget",
391 @"regularwin", @"windowtype",
392 (bDrawActive ? @"normal" : @"inactive"), @"state",
393 [NSNumber numberWithDouble:unifiedHeight], @"kCUIWindowFrameUnifiedTitleBarHeightKey",
394 [NSNumber numberWithBool:NO], @"kCUIWindowFrameDrawTitleSeparatorKey",
395 [NSNumber numberWithBool:YES], @"is.flipped",
396 nil]),
397 nil);
399 else
401 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
402 aMenuItemDrawInfo.version = 0;
403 aMenuItemDrawInfo.state = kThemeMenuActive;
404 aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
405 HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, mrContext, kHIThemeOrientationNormal, nullptr);
407 #endif
408 bOK = true;
410 break;
412 case ControlType::WindowBackground:
414 HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
415 aThemeBackgroundInfo.version = 0;
416 aThemeBackgroundInfo.state = getState( nState );
417 aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundActive;
418 // FIXME: without this magical offset there is a 2 pixel black border on the right and bottom
419 rc.size.width += 2;
420 rc.size.height += 2;
422 HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, mrContext, kHIThemeOrientationNormal);
423 CGContextFillRect( mrContext, rc );
424 bOK = true;
426 break;
428 case ControlType::Menubar:
429 case ControlType::MenuPopup:
431 if ((nPart == ControlPart::Entire) || (nPart == ControlPart::MenuItem )|| (nPart == ControlPart::HasBackgroundTexture ))
433 // FIXME: without this magical offset there is a 2 pixel black border on the right
434 rc.size.width += 2;
436 HIThemeMenuDrawInfo aMenuInfo;
437 aMenuInfo.version = 0;
438 aMenuInfo.menuType = kThemeMenuTypePullDown;
440 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
441 // the Aqua grey theme when the item is selected is drawn here.
442 aMenuItemDrawInfo.itemType = kThemeMenuItemPlain;
444 if ((nPart == ControlPart::MenuItem ) && (nState & ControlState::SELECTED))
446 // the blue theme when the item is selected is drawn here.
447 aMenuItemDrawInfo.state = kThemeMenuSelected;
449 else
451 // normal color for non selected item
452 aMenuItemDrawInfo.state = kThemeMenuActive;
455 // repaints the background of the pull down menu
456 HIThemeDrawMenuBackground(&rc,&aMenuInfo,mrContext,kHIThemeOrientationNormal);
458 // repaints the item either blue (selected) and/or Aqua grey (active only)
459 HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,&rc);
461 bOK = true;
463 else if(( nPart == ControlPart::MenuItemCheckMark )||( nPart == ControlPart::MenuItemRadioMark )) {
464 if( nState & ControlState::PRESSED ) {//checked, else it is not displayed (see vcl/source/window/menu.cxx)
465 HIThemeTextInfo aTextInfo;
466 aTextInfo.version = 0;
467 aTextInfo.state = (nState & ControlState::ENABLED) ? kThemeStateInactive: kThemeStateActive;
468 aTextInfo.fontID = kThemeMenuItemMarkFont;
469 aTextInfo.horizontalFlushness=kHIThemeTextHorizontalFlushCenter;
470 aTextInfo.verticalFlushness=kHIThemeTextVerticalFlushTop;
471 aTextInfo.options=kHIThemeTextBoxOptionNone;
472 aTextInfo.truncationPosition=kHIThemeTextTruncationNone;
473 //aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone
475 if( nState & ControlState::SELECTED) aTextInfo.state = kThemeStatePressed; //item highlighted
477 UniChar mark=( nPart == ControlPart::MenuItemCheckMark ) ? kCheckUnicode: kBulletUnicode;//0x2713;
478 CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull);
479 HIThemeDrawTextBox(cfString, &rc, &aTextInfo, mrContext, kHIThemeOrientationNormal);
480 if (cfString)
481 CFRelease(cfString);
483 bOK = true;
487 break;
489 case ControlType::Pushbutton:
491 // [ FIXME] : instead of use a value, vcl can retrieve correct values on the fly (to be implemented)
492 const int PB_Mini_Height = 15;
493 const int PB_Norm_Height = 21;
495 HIThemeButtonDrawInfo aPushInfo;
496 aPushInfo.version = 0;
498 // no animation
499 aPushInfo.animation.time.start = 0;
500 aPushInfo.animation.time.current = 0;
501 PushButtonValue const * pPBVal = aValue.getType() == ControlType::Pushbutton ? static_cast<PushButtonValue const *>(&aValue) : nullptr;
502 int nPaintHeight = static_cast<int>(rc.size.height);
504 if( pPBVal && pPBVal->mbBevelButton )
506 aPushInfo.kind = kThemeRoundedBevelButton;
508 else if( rc.size.height <= PB_Norm_Height )
510 aPushInfo.kind = kThemePushButtonMini;
511 nPaintHeight = PB_Mini_Height;
513 else if( (pPBVal && pPBVal->mbSingleLine) || rc.size.height < (PB_Norm_Height + PB_Norm_Height/2) )
515 aPushInfo.kind = kThemePushButtonNormal;
516 nPaintHeight = PB_Norm_Height;
518 // avoid clipping when focused
519 rc.origin.x += FOCUS_RING_WIDTH/2;
520 rc.size.width -= FOCUS_RING_WIDTH;
522 if( nState & ControlState::DEFAULT )
524 AquaBlinker::Blink( mpFrame, buttonRect );
525 // show correct animation phase
526 aPushInfo.animation.time.current = CFAbsoluteTimeGetCurrent();
529 else
530 aPushInfo.kind = kThemeBevelButton;
532 // translate the origin for controls with fixed paint height
533 // so content ends up somewhere sensible
534 int delta_y = static_cast<int>(rc.size.height) - nPaintHeight;
535 rc.origin.y += delta_y/2;
537 aPushInfo.state = getState( nState );
538 aPushInfo.value = ImplGetButtonValue( aValue.getTristateVal() );
540 aPushInfo.adornment = ( nState & ControlState::DEFAULT ) ?
541 kThemeAdornmentDefault :
542 kThemeAdornmentNone;
543 if( nState & ControlState::FOCUSED )
544 aPushInfo.adornment |= kThemeAdornmentFocus;
546 HIThemeDrawButton( &rc, &aPushInfo, mrContext, kHIThemeOrientationNormal, nullptr );
547 bOK = true;
549 break;
551 case ControlType::Radiobutton:
552 case ControlType::Checkbox:
554 HIThemeButtonDrawInfo aInfo;
555 aInfo.version = 0;
556 switch( nType )
558 case ControlType::Radiobutton: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeRadioButton;
559 else aInfo.kind = kThemeSmallRadioButton;
560 break;
561 case ControlType::Checkbox: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeCheckBox;
562 else aInfo.kind = kThemeSmallCheckBox;
563 break;
564 default: break;
567 aInfo.state = getState( nState );
569 ButtonValue aButtonValue = aValue.getTristateVal();
570 aInfo.value = ImplGetButtonValue( aButtonValue );
572 aInfo.adornment = ( nState & ControlState::DEFAULT ) ?
573 kThemeAdornmentDefault :
574 kThemeAdornmentNone;
575 if( nState & ControlState::FOCUSED )
576 aInfo.adornment |= kThemeAdornmentFocus;
577 HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, nullptr );
578 bOK = true;
580 break;
582 case ControlType::ListNode:
584 ButtonValue aButtonValue = aValue.getTristateVal();
586 if( AllSettings::GetLayoutRTL() && aButtonValue == ButtonValue::Off )
588 // FIXME: a value of kThemeDisclosureLeft
589 // should draw a theme compliant left disclosure triangle
590 // sadly this does not seem to work, so we'll draw a left
591 // grey equilateral triangle here ourselves.
592 // Perhaps some other HIThemeButtonDrawInfo setting would do the trick ?
594 CGContextSetShouldAntialias( mrContext, true );
595 CGFloat aGrey[] = { 0.45, 0.45, 0.45, 1.0 };
596 CGContextSetFillColor( mrContext, aGrey );
597 CGContextBeginPath( mrContext );
598 float x = rc.origin.x + rc.size.width;
599 float y = rc.origin.y;
600 CGContextMoveToPoint( mrContext, x, y );
601 y += rc.size.height;
602 CGContextAddLineToPoint( mrContext, x, y );
603 x -= rc.size.height * 0.866; // cos( 30 degree ) is approx. 0.866
604 y -= rc.size.height/2;
605 CGContextAddLineToPoint( mrContext, x, y );
606 CGContextDrawPath( mrContext, kCGPathEOFill );
608 else
610 HIThemeButtonDrawInfo aInfo;
611 aInfo.version = 0;
612 aInfo.kind = kThemeDisclosureTriangle;
613 aInfo.value = kThemeDisclosureRight;
614 aInfo.state = getState( nState );
616 aInfo.adornment = kThemeAdornmentNone;
618 switch( aButtonValue ) {
619 case ButtonValue::On: aInfo.value = kThemeDisclosureDown;//expanded
620 break;
621 case ButtonValue::Off:
622 // FIXME: this should have drawn a theme compliant disclosure triangle
623 // (see above)
624 if( AllSettings::GetLayoutRTL() )
626 aInfo.value = kThemeDisclosureLeft;//collapsed, RTL
628 break;
629 case ButtonValue::DontKnow: //what to do?
630 default:
631 break;
634 HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, nullptr );
636 bOK = true;
638 break;
640 case ControlType::Progress:
641 case ControlType::IntroProgress:
643 long nProgressWidth = aValue.getNumericVal();
644 HIThemeTrackDrawInfo aTrackInfo;
645 aTrackInfo.version = 0;
646 aTrackInfo.kind = (rc.size.height > 10) ? kThemeProgressBarLarge : kThemeProgressBarMedium;
647 aTrackInfo.bounds = rc;
648 aTrackInfo.min = 0;
649 aTrackInfo.max = static_cast<SInt32>(rc.size.width);
650 aTrackInfo.value = nProgressWidth;
651 aTrackInfo.reserved = 0;
652 aTrackInfo.bounds.origin.y -= 2; // FIXME: magic for shadow
653 aTrackInfo.bounds.size.width -= 2; // FIXME: magic for shadow
654 aTrackInfo.attributes = kThemeTrackHorizontal;
655 if( AllSettings::GetLayoutRTL() )
656 aTrackInfo.attributes |= kThemeTrackRightToLeft;
657 aTrackInfo.enableState = getTrackState( nState );
658 // the intro bitmap never gets key anyway; we want to draw that enabled
659 if( nType == ControlType::IntroProgress )
660 aTrackInfo.enableState = kThemeTrackActive;
661 aTrackInfo.filler1 = 0;
662 aTrackInfo.trackInfo.progress.phase = static_cast<long long>(CFAbsoluteTimeGetCurrent()*10.0);
664 HIThemeDrawTrack( &aTrackInfo, nullptr, mrContext, kHIThemeOrientationNormal );
665 bOK = true;
667 break;
669 case ControlType::Slider:
671 SliderValue const * pSLVal = static_cast<SliderValue const *>(&aValue);
673 HIThemeTrackDrawInfo aTrackDraw;
674 aTrackDraw.kind = kThemeSliderMedium;
675 if( nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea )
677 aTrackDraw.bounds = rc;
678 aTrackDraw.min = pSLVal->mnMin;
679 aTrackDraw.max = pSLVal->mnMax;
680 aTrackDraw.value = pSLVal->mnCur;
681 aTrackDraw.reserved = 0;
682 aTrackDraw.attributes = kThemeTrackShowThumb;
683 if( nPart == ControlPart::TrackHorzArea )
684 aTrackDraw.attributes |= kThemeTrackHorizontal;
685 aTrackDraw.enableState = (nState & ControlState::ENABLED)
686 ? kThemeTrackActive : kThemeTrackInactive;
688 SliderTrackInfo aSlideInfo;
689 aSlideInfo.thumbDir = kThemeThumbUpward;
690 aSlideInfo.pressState = 0;
691 aTrackDraw.trackInfo.slider = aSlideInfo;
693 HIThemeDrawTrack( &aTrackDraw, nullptr, mrContext, kHIThemeOrientationNormal );
694 bOK = true;
697 break;
699 case ControlType::Scrollbar:
701 const ScrollbarValue* pScrollbarVal = (aValue.getType() == ControlType::Scrollbar) ? static_cast<const ScrollbarValue*>(&aValue) : nullptr;
703 if( nPart == ControlPart::DrawBackgroundVert ||
704 nPart == ControlPart::DrawBackgroundHorz )
706 HIThemeTrackDrawInfo aTrackDraw;
707 aTrackDraw.kind = kThemeMediumScrollBar;
708 // FIXME: the scrollbar length must be adjusted
709 if (nPart == ControlPart::DrawBackgroundVert)
710 rc.size.height += 2;
711 else
712 rc.size.width += 2;
714 aTrackDraw.bounds = rc;
715 aTrackDraw.min = pScrollbarVal->mnMin;
716 aTrackDraw.max = pScrollbarVal->mnMax - pScrollbarVal->mnVisibleSize;
717 aTrackDraw.value = pScrollbarVal->mnCur;
718 aTrackDraw.reserved = 0;
719 aTrackDraw.attributes = kThemeTrackShowThumb;
720 if( nPart == ControlPart::DrawBackgroundHorz )
721 aTrackDraw.attributes |= kThemeTrackHorizontal;
722 aTrackDraw.enableState = getTrackState( nState );
724 ScrollBarTrackInfo aScrollInfo;
725 aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize;
726 aScrollInfo.pressState = 0;
728 if ( pScrollbarVal->mnButton1State & ControlState::ENABLED )
730 if ( pScrollbarVal->mnButton1State & ControlState::PRESSED )
731 aScrollInfo.pressState = kThemeTopOutsideArrowPressed;
734 if ( pScrollbarVal->mnButton2State & ControlState::ENABLED )
736 if ( pScrollbarVal->mnButton2State & ControlState::PRESSED )
737 aScrollInfo.pressState = kThemeBottomOutsideArrowPressed;
740 if ( pScrollbarVal->mnThumbState & ControlState::ENABLED )
742 if ( pScrollbarVal->mnThumbState & ControlState::PRESSED )
743 aScrollInfo.pressState = kThemeThumbPressed;
746 aTrackDraw.trackInfo.scrollbar = aScrollInfo;
748 HIThemeDrawTrack( &aTrackDraw, nullptr, mrContext, kHIThemeOrientationNormal );
749 bOK = true;
752 break;
754 case ControlType::TabPane:
756 HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
757 aTabPaneDrawInfo.version = 1;
758 aTabPaneDrawInfo.state = kThemeStateActive;
759 aTabPaneDrawInfo.direction=kThemeTabNorth;
760 aTabPaneDrawInfo.size=kHIThemeTabSizeNormal;
761 aTabPaneDrawInfo.kind=kHIThemeTabKindNormal;
763 //the border is outside the rect rc for Carbon
764 //but for VCL it should be inside
765 rc.origin.x+=1;
766 rc.origin.y-=TAB_HEIGHT_NORMAL/2;
767 rc.size.height+=TAB_HEIGHT_NORMAL/2;
768 rc.size.width-=2;
770 HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal);
772 bOK = true;
774 break;
776 case ControlType::TabItem:
778 HIThemeTabDrawInfo aTabItemDrawInfo;
779 aTabItemDrawInfo.version=1;
780 aTabItemDrawInfo.style=kThemeTabNonFront;
781 aTabItemDrawInfo.direction=kThemeTabNorth;
782 aTabItemDrawInfo.size=kHIThemeTabSizeNormal;
783 aTabItemDrawInfo.adornment=kHIThemeTabAdornmentTrailingSeparator;
784 //State
785 if(nState & ControlState::SELECTED) {
786 aTabItemDrawInfo.style=kThemeTabFront;
788 if(nState & ControlState::FOCUSED) {
789 aTabItemDrawInfo.adornment|=kHIThemeTabAdornmentFocus;
792 //first, last or middle tab
793 aTabItemDrawInfo.position=kHIThemeTabPositionMiddle;
795 TabitemValue const * pTabValue = static_cast<TabitemValue const *>(&aValue);
796 TabitemFlags nAlignment = pTabValue->mnAlignment;
797 //TabitemFlags::LeftAligned (and TabitemFlags::RightAligned) for the leftmost (or rightmost) tab
798 //when there are several lines of tabs because there is only one first tab and one
799 //last tab and TabitemFlags::FirstInGroup (and TabitemFlags::LastInGroup) because when the
800 //line width is different from window width, there may not be TabitemFlags::RightAligned
801 if( ( (nAlignment & TabitemFlags::LeftAligned)&&(nAlignment & TabitemFlags::RightAligned) ) ||
802 ( (nAlignment & TabitemFlags::FirstInGroup)&&(nAlignment & TabitemFlags::LastInGroup) )
803 ) //tab alone
804 aTabItemDrawInfo.position=kHIThemeTabPositionOnly;
805 else if((nAlignment & TabitemFlags::LeftAligned)||(nAlignment & TabitemFlags::FirstInGroup))
806 aTabItemDrawInfo.position=kHIThemeTabPositionFirst;
807 else if((nAlignment & TabitemFlags::RightAligned)||(nAlignment & TabitemFlags::LastInGroup))
808 aTabItemDrawInfo.position=kHIThemeTabPositionLast;
810 //support for RTL
811 //see issue 79748
812 if( AllSettings::GetLayoutRTL() ) {
813 if( aTabItemDrawInfo.position == kHIThemeTabPositionFirst )
814 aTabItemDrawInfo.position = kHIThemeTabPositionLast;
815 else if( aTabItemDrawInfo.position == kHIThemeTabPositionLast )
816 aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
819 rc.size.width+=2;//because VCL has 2 empty pixels between 2 tabs
820 rc.origin.x-=1;
822 HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc );
824 bOK=true;
826 break;
828 case ControlType::Listbox:
829 switch( nPart)
831 case ControlPart::Entire:
832 case ControlPart::ButtonDown:
834 HIThemeButtonDrawInfo aListInfo;
835 aListInfo.version = 0;
836 aListInfo.kind = kThemePopupButton;
837 aListInfo.state = getState( nState );//kThemeStateInactive -> greyed
838 aListInfo.value = kThemeButtonOn;
840 aListInfo.adornment = kThemeAdornmentDefault;
841 if( nState & ControlState::FOCUSED )
842 aListInfo.adornment |= kThemeAdornmentFocus;
844 HIThemeDrawButton(&rc, &aListInfo, mrContext, kHIThemeOrientationNormal,&rc);
845 bOK = true;
846 break;
848 case ControlPart::ListboxWindow:
850 HIThemeFrameDrawInfo aTextDrawInfo;
851 aTextDrawInfo.version=0;
852 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
853 aTextDrawInfo.state=getState( nState );
854 aTextDrawInfo.isFocused=false;
856 rc.size.width+=1;//else there's a white space because an OS X theme has no 3D border
857 rc.size.height+=1;
858 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
860 if(nState & ControlState::FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
862 bOK=true;
863 break;
865 default: break;
867 break;
869 case ControlType::Editbox:
870 case ControlType::MultilineEditbox:
872 HIThemeFrameDrawInfo aTextDrawInfo;
873 aTextDrawInfo.version=0;
874 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
875 aTextDrawInfo.state=getState( nState );
876 aTextDrawInfo.isFocused=false;
878 rc.size.width += 1; // else there may be a white space because an OS X theme has no 3D border
879 // change rc so that the frame will encompass only the content region
880 // see counterpart in GetNativeControlRegion
881 rc.size.width += 2;
882 rc.size.height += 2;
884 //CGContextSetFillColorWithColor
885 CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
886 //fill a white background, because drawFrame only draws the border
888 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
890 if(nState & ControlState::FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
892 bOK=true;
894 break;
896 case ControlType::Spinbox:
898 if(nPart == ControlPart::Entire)
900 //text field:
901 HIThemeFrameDrawInfo aTextDrawInfo;
902 aTextDrawInfo.version=0;
903 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
904 aTextDrawInfo.state=getState( nState );
905 aTextDrawInfo.isFocused=false;
907 //rc.size.width contains the full size of the spinbox ie textfield + button
908 //so we remove the button width and the space between the button and the textfield
909 rc.size.width -= SPIN_BUTTON_SPACE + SPIN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
910 rc.origin.x += FOCUS_RING_WIDTH;
911 rc.origin.y += FOCUS_RING_WIDTH;
913 //CGContextSetFillColorWithColor
914 CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
915 //fill a white background, because drawFrame only draws the border
917 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
919 if(nState & ControlState::FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
921 //buttons:
922 const SpinbuttonValue* pSpinButtonVal = (aValue.getType() == ControlType::SpinButtons) ? static_cast<const SpinbuttonValue*>(&aValue) : nullptr;
923 ControlState nUpperState = ControlState::ENABLED;//state of the upper button
924 ControlState nLowerState = ControlState::ENABLED;//and of the lower button
925 if(pSpinButtonVal) {//pSpinButtonVal is sometimes null
926 nUpperState = (ControlState) pSpinButtonVal->mnUpperState;
927 nLowerState = (ControlState) pSpinButtonVal->mnLowerState;
929 HIThemeButtonDrawInfo aSpinInfo;
930 aSpinInfo.kind = kThemeIncDecButton;
931 aSpinInfo.state = kThemeStateActive;
932 if(nUpperState & ControlState::PRESSED)
933 aSpinInfo.state = kThemeStatePressedUp;
934 else if(nLowerState & ControlState::PRESSED)
935 aSpinInfo.state = kThemeStatePressedDown;
936 else if((nUpperState & ~ControlState::ENABLED)||(nLowerState & ~ControlState::ENABLED))
937 aSpinInfo.state = kThemeStateInactive;
938 else if((nUpperState & ControlState::ROLLOVER)||(nLowerState & ControlState::ROLLOVER))
939 aSpinInfo.state = kThemeStateRollover;
941 tools::Rectangle aSpinRect( pSpinButtonVal->maUpperRect );
942 aSpinRect.Union( pSpinButtonVal->maLowerRect );
943 HIRect buttonRc = ImplGetHIRectFromRectangle(aSpinRect);
945 // FIXME: without this fuzz factor there is some unwanted clipping
946 if( AllSettings::GetLayoutRTL() )
947 buttonRc.origin.x -= FOCUS_RING_WIDTH - CLIP_FUZZ;
948 else
949 buttonRc.origin.x += FOCUS_RING_WIDTH + CLIP_FUZZ;
951 switch( aValue.getTristateVal() )
953 case ButtonValue::On: aSpinInfo.value = kThemeButtonOn;
954 break;
955 case ButtonValue::Off: aSpinInfo.value = kThemeButtonOff;
956 break;
957 case ButtonValue::Mixed:
958 case ButtonValue::DontKnow:
959 default: aSpinInfo.value = kThemeButtonMixed;
960 break;
963 aSpinInfo.adornment = ( (nUpperState & ControlState::DEFAULT) ||
964 (nLowerState & ControlState::DEFAULT) ) ?
965 kThemeAdornmentDefault :
966 kThemeAdornmentNone;
967 if( (nUpperState & ControlState::FOCUSED) || (nLowerState & ControlState::FOCUSED))
968 aSpinInfo.adornment |= kThemeAdornmentFocus;
970 HIThemeDrawButton( &buttonRc, &aSpinInfo, mrContext, kHIThemeOrientationNormal, nullptr );
973 bOK=true;
977 break;
979 case ControlType::Frame:
981 DrawFrameFlags nStyle = static_cast<DrawFrameFlags>(aValue.getNumericVal());
982 if( nPart == ControlPart::Border ) {
983 if(!( nStyle & DrawFrameFlags::Menu ) && !(nStyle & DrawFrameFlags::WindowBorder) )
985 // #i84756# strange effects start to happen when HIThemeDrawFrame
986 // meets the border of the window. These can be avoided by clipping
987 // to the boundary of the frame
988 if( rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight-3 )
990 CGMutablePathRef rPath = CGPathCreateMutable();
991 CGPathAddRect( rPath, nullptr, CGRectMake( 0, 0, mpFrame->maGeometry.nWidth-1, mpFrame->maGeometry.nHeight-1 ) );
993 CGContextBeginPath( mrContext );
994 CGContextAddPath( mrContext, rPath );
995 CGContextClip( mrContext );
996 CGPathRelease( rPath );
999 HIThemeFrameDrawInfo aTextDrawInfo;
1000 aTextDrawInfo.version=0;
1001 aTextDrawInfo.kind=kHIThemeFrameListBox;
1002 aTextDrawInfo.state=kThemeStateActive;
1003 aTextDrawInfo.isFocused=false;
1005 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
1007 bOK=true;
1011 break;
1013 case ControlType::ListNet:
1015 //do nothing as there isn't net for listviews on macos
1016 bOK=true;
1018 break;
1019 default: break;
1022 CGContextRestoreGState( mrContext );
1024 /* #i90291# in most cases invalidating the whole control region instead
1025 of just the unclipped part of it is sufficient (and probably faster).
1026 However for the window background we should not unnecessarily enlarge
1027 the really changed rectangle since the difference is usually quite high
1028 (the background is always drawn as a whole since we don't know anything
1029 about its possible contents)
1031 if( nType == ControlType::WindowBackground )
1033 CGRect aRect = { { 0, 0 }, { 0, 0 } };
1034 if( mxClipPath )
1035 aRect = CGPathGetBoundingBox( mxClipPath );
1036 if( aRect.size.width != 0 && aRect.size.height != 0 )
1037 buttonRect.Intersection( tools::Rectangle( Point( static_cast<long int>(aRect.origin.x),
1038 static_cast<long int>(aRect.origin.y) ),
1039 Size( static_cast<long int>(aRect.size.width),
1040 static_cast<long int>(aRect.size.height) ) ) );
1043 RefreshRect( buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight() );
1045 return bOK;
1048 bool AquaSalGraphics::getNativeControlRegion( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, ControlState /*nState*/,
1049 const ImplControlValue& aValue, const OUString&,
1050 tools::Rectangle &rNativeBoundingRegion, tools::Rectangle &rNativeContentRegion )
1053 bool toReturn = false;
1055 tools::Rectangle aCtrlBoundRect( rControlRegion );
1056 short x = aCtrlBoundRect.Left();
1057 short y = aCtrlBoundRect.Top();
1058 short w, h;
1060 sal_uInt8 nBorderCleanup = 0;
1062 switch (nType)
1064 case ControlType::Slider:
1066 if( nPart == ControlPart::ThumbHorz )
1068 w = 19; // taken from HIG
1069 h = aCtrlBoundRect.GetHeight();
1070 rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1071 toReturn = true;
1073 else if( nPart == ControlPart::ThumbVert )
1075 w = aCtrlBoundRect.GetWidth();
1076 h = 18; // taken from HIG
1077 rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1078 toReturn = true;
1081 break;
1083 case ControlType::Scrollbar:
1085 tools::Rectangle aRect;
1086 if( AquaGetScrollRect( /* m_nScreen */ nPart, aCtrlBoundRect, aRect ) )
1088 toReturn = true;
1089 rNativeBoundingRegion = aRect;
1090 rNativeContentRegion = aRect;
1093 break;
1095 case ControlType::Pushbutton:
1096 case ControlType::Radiobutton:
1097 case ControlType::Checkbox:
1099 if ( nType == ControlType::Pushbutton )
1101 w = aCtrlBoundRect.GetWidth();
1102 h = aCtrlBoundRect.GetHeight();
1104 else
1106 // checkbox and radio borders need cleanup after unchecking them
1107 nBorderCleanup = 4;
1109 // TEXT_SEPARATOR to respect Aqua HIG
1110 w = BUTTON_WIDTH + TEXT_SEPARATOR;
1111 h = BUTTON_HEIGHT;
1115 rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h + nBorderCleanup) );
1116 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1118 toReturn = true;
1120 break;
1121 case ControlType::Progress:
1123 tools::Rectangle aRect( aCtrlBoundRect );
1124 if( aRect.GetHeight() < 16 )
1125 aRect.Bottom() = aRect.Top() + 9; // values taken from HIG for medium progress
1126 else
1127 aRect.Bottom() = aRect.Top() + 15; // values taken from HIG for large progress
1128 rNativeBoundingRegion = aRect;
1129 rNativeContentRegion = aRect;
1130 toReturn = true;
1132 break;
1134 case ControlType::IntroProgress:
1136 tools::Rectangle aRect( aCtrlBoundRect );
1137 aRect.Bottom() = aRect.Top() + INTRO_PROGRESS_HEIGHT; // values taken from HIG for medium progress
1138 rNativeBoundingRegion = aRect;
1139 rNativeContentRegion = aRect;
1140 toReturn = true;
1142 break;
1144 case ControlType::TabItem:
1146 w = aCtrlBoundRect.GetWidth() + 2*TAB_TEXT_OFFSET - 2*VCL_TAB_TEXT_OFFSET;
1147 h = TAB_HEIGHT_NORMAL+2;
1149 rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1150 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1152 toReturn = true;
1154 break;
1156 case ControlType::Editbox:
1158 w = aCtrlBoundRect.GetWidth();
1159 if( w < 3+2*FOCUS_RING_WIDTH )
1160 w = 3+2*FOCUS_RING_WIDTH;
1161 h = TEXT_EDIT_HEIGHT_NORMAL+2*FOCUS_RING_WIDTH;
1162 if( h < aCtrlBoundRect.GetHeight() )
1163 h = aCtrlBoundRect.GetHeight();
1165 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) ) );
1166 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1168 toReturn = true;
1170 break;
1171 case ControlType::Listbox:
1172 case ControlType::Combobox:
1174 if( nPart == ControlPart::Entire )
1176 w = aCtrlBoundRect.GetWidth();
1177 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
1179 rNativeContentRegion = tools::Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*FOCUS_RING_WIDTH, h ) );
1180 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1182 toReturn = true;
1184 else if( nPart == ControlPart::ButtonDown )
1186 w = aCtrlBoundRect.GetWidth();
1187 if( w < 3+2*FOCUS_RING_WIDTH )
1188 w = 3+2*FOCUS_RING_WIDTH;
1189 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
1191 x += w-DROPDOWN_BUTTON_WIDTH - FOCUS_RING_WIDTH;
1192 y += FOCUS_RING_WIDTH;
1193 w = DROPDOWN_BUTTON_WIDTH;
1195 rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1196 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
1198 toReturn = true;
1200 else if( nPart == ControlPart::SubEdit )
1202 w = aCtrlBoundRect.GetWidth();
1203 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
1205 x += FOCUS_RING_WIDTH;
1206 x += 3; // add an offset for rounded borders
1207 y += 2; // don't draw into upper border
1208 y += FOCUS_RING_WIDTH;
1209 w -= 3 + DROPDOWN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
1210 if( nType == ControlType::Listbox )
1211 w -= 9; // HIG specifies 9 units distance between dropdown button area and content
1212 h -= 4; // don't draw into lower border
1214 rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1215 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
1217 toReturn = true;
1220 break;
1221 case ControlType::Spinbox:
1222 if( nPart == ControlPart::Entire ) {
1223 w = aCtrlBoundRect.GetWidth();
1224 if( w < 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH )
1225 w = 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH;
1226 h = TEXT_EDIT_HEIGHT_NORMAL;
1228 rNativeContentRegion = tools::Rectangle( Point( x+FOCUS_RING_WIDTH, y ), Size( w-2*FOCUS_RING_WIDTH, h ) );
1229 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1231 toReturn = true;
1233 else if( nPart == ControlPart::SubEdit ) {
1234 w = aCtrlBoundRect.GetWidth() - SPIN_BUTTON_SPACE - SPIN_BUTTON_WIDTH;
1235 h = TEXT_EDIT_HEIGHT_NORMAL;
1236 x += 4; // add an offset for rounded borders
1237 y += 2; // don't draw into upper border
1238 w -= 8; // offset for left and right rounded border
1239 h -= 4; // don't draw into upper or lower border
1241 rNativeContentRegion = tools::Rectangle( Point( x + FOCUS_RING_WIDTH, y + FOCUS_RING_WIDTH ), Size( w - 2* FOCUS_RING_WIDTH, h ) );
1242 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1244 toReturn = true;
1246 else if( nPart == ControlPart::ButtonUp ) {
1247 //aCtrlBoundRect.GetWidth() contains the width of the full control
1248 //ie the width of the textfield + button
1249 //x is the position of the left corner of the full control
1250 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
1251 y += FOCUS_RING_WIDTH - CLIP_FUZZ;
1252 w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
1253 h = SPIN_UPPER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
1255 rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1256 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1258 toReturn = true;
1260 else if( nPart == ControlPart::ButtonDown ) {
1261 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
1262 y += SPIN_UPPER_BUTTON_HEIGHT + FOCUS_RING_WIDTH - CLIP_FUZZ;
1263 w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
1264 h = SPIN_LOWER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
1266 rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1267 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1269 toReturn = true;
1271 break;
1272 case ControlType::Frame:
1274 DrawFrameStyle nStyle = static_cast<DrawFrameStyle>(aValue.getNumericVal() & 0x000f);
1275 DrawFrameFlags nFlags = static_cast<DrawFrameFlags>(aValue.getNumericVal() & 0xfff0);
1276 if( ( nPart == ControlPart::Border ) &&
1277 !( nFlags & (DrawFrameFlags::Menu | DrawFrameFlags::WindowBorder | DrawFrameFlags::BorderWindowBorder) ) )
1279 tools::Rectangle aRect(aCtrlBoundRect);
1280 if( nStyle == DrawFrameStyle::DoubleIn )
1282 aRect.Left() += 1;
1283 aRect.Top() += 1;
1284 //rRect.Right() -= 1;
1285 //rRect.Bottom() -= 1;
1287 else
1289 aRect.Left() += 1;
1290 aRect.Top() += 1;
1291 aRect.Right() -= 1;
1292 aRect.Bottom() -= 1;
1295 rNativeContentRegion = aRect;
1296 rNativeBoundingRegion = aRect;
1298 toReturn = true;
1301 break;
1303 case ControlType::Menubar:
1304 case ControlType::MenuPopup:
1306 if(( nPart == ControlPart::MenuItemCheckMark )||( nPart == ControlPart::MenuItemRadioMark )) {
1308 w=10;
1309 h=10;//dimensions of the mark (10px font)
1311 rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1312 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1314 toReturn = true;
1317 break;
1318 default: break;
1322 return toReturn;
1325 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */