Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / vcl / osx / salnativewidgets.cxx
blob6e94cd3e4df3732cc61c3eb8b33a742c5e93bcd1
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 // Helper returns an HIRect
49 static HIRect ImplGetHIRectFromRectangle(tools::Rectangle aRect)
51 HIRect aHIRect;
52 aHIRect.origin.x = static_cast<float>(aRect.Left());
53 aHIRect.origin.y = static_cast<float>(aRect.Top());
54 aHIRect.size.width = static_cast<float>(aRect.GetWidth());
55 aHIRect.size.height = static_cast<float>(aRect.GetHeight());
56 return aHIRect;
59 static ThemeButtonValue ImplGetButtonValue( ButtonValue aButtonValue )
61 switch( aButtonValue )
63 case ButtonValue::On:
64 return kThemeButtonOn;
65 break;
67 case ButtonValue::Off:
68 case ButtonValue::DontKnow:
69 return kThemeButtonOff;
70 break;
72 case ButtonValue::Mixed:
73 default:
74 return kThemeButtonMixed;
75 break;
79 static bool AquaGetScrollRect( /* TODO: int nScreen, */ ControlPart nPart,
80 const tools::Rectangle& rControlRect, tools::Rectangle& rResultRect )
82 bool bRetVal = true;
83 rResultRect = rControlRect;
85 switch( nPart )
87 case ControlPart::ButtonUp:
88 rResultRect.SetBottom( rResultRect.Top() );
89 break;
91 case ControlPart::ButtonDown:
92 rResultRect.SetTop( rResultRect.Bottom() );
93 break;
95 case ControlPart::ButtonLeft:
96 rResultRect.SetRight( rResultRect.Left() );
97 break;
99 case ControlPart::ButtonRight:
100 rResultRect.SetLeft( rResultRect.Right() );
101 break;
103 case ControlPart::TrackHorzArea:
104 case ControlPart::TrackVertArea:
105 case ControlPart::ThumbHorz:
106 case ControlPart::ThumbVert:
107 case ControlPart::TrackHorzLeft:
108 case ControlPart::TrackHorzRight:
109 case ControlPart::TrackVertUpper:
110 case ControlPart::TrackVertLower:
111 break;
112 default:
113 bRetVal = false;
116 return bRetVal;
119 bool AquaSalGraphics::isNativeControlSupported( ControlType nType, ControlPart nPart )
121 // Native controls are now defaults
122 // If you want to disable experimental native controls code,
123 // just set the environment variable SAL_NO_NWF to something
124 // and vcl controls will be used as default again.
126 switch( nType )
128 case ControlType::Pushbutton:
129 case ControlType::Radiobutton:
130 case ControlType::Checkbox:
131 case ControlType::ListNode:
132 if( nPart == ControlPart::Entire )
133 return true;
134 break;
136 case ControlType::Scrollbar:
137 if( nPart == ControlPart::DrawBackgroundHorz ||
138 nPart == ControlPart::DrawBackgroundVert ||
139 nPart == ControlPart::Entire ||
140 nPart == ControlPart::HasThreeButtons )
141 return true;
142 break;
144 case ControlType::Slider:
145 if( nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea )
146 return true;
147 break;
149 case ControlType::Editbox:
150 if( nPart == ControlPart::Entire ||
151 nPart == ControlPart::HasBackgroundTexture )
152 return true;
153 break;
155 case ControlType::MultilineEditbox:
156 if( nPart == ControlPart::Entire ||
157 nPart == ControlPart::HasBackgroundTexture )
158 return true;
159 break;
161 case ControlType::Spinbox:
162 if( nPart == ControlPart::Entire ||
163 nPart == ControlPart::AllButtons ||
164 nPart == ControlPart::HasBackgroundTexture )
165 return true;
166 break;
168 case ControlType::SpinButtons:
169 return false;
170 break;
172 case ControlType::Combobox:
173 if( nPart == ControlPart::Entire ||
174 nPart == ControlPart::HasBackgroundTexture )
175 return true;
176 break;
178 case ControlType::Listbox:
179 if( nPart == ControlPart::Entire ||
180 nPart == ControlPart::ListboxWindow ||
181 nPart == ControlPart::HasBackgroundTexture ||
182 nPart == ControlPart::SubEdit
184 return true;
185 break;
187 case ControlType::TabItem:
188 case ControlType::TabPane:
189 case ControlType::TabBody: // see vcl/source/window/tabpage.cxx
190 if( nPart == ControlPart::Entire ||
191 nPart == ControlPart::TabsDrawRtl ||
192 nPart == ControlPart::HasBackgroundTexture )
193 return true;
194 break;
196 // when ControlPart::Button is used, toolbar icons are not highlighted when mouse rolls over.
197 // More Aqua compliant
198 case ControlType::Toolbar:
199 if( nPart == ControlPart::Entire ||
200 nPart == ControlPart::DrawBackgroundHorz ||
201 nPart == ControlPart::DrawBackgroundVert)
202 return true;
203 break;
205 case ControlType::WindowBackground:
206 if ( nPart == ControlPart::BackgroundWindow ||
207 nPart == ControlPart::BackgroundDialog )
208 return true;
209 break;
211 case ControlType::Menubar:
212 if( nPart == ControlPart::Entire )
213 return true;
214 break;
216 case ControlType::Tooltip: // ** TO DO
217 if (nPart == ControlPart::Entire)
218 return true;
219 break;
221 case ControlType::MenuPopup:
222 if( nPart == ControlPart::Entire ||
223 nPart == ControlPart::MenuItem ||
224 nPart == ControlPart::MenuItemCheckMark ||
225 nPart == ControlPart::MenuItemRadioMark)
226 return true;
227 break;
228 case ControlType::Progress:
229 case ControlType::IntroProgress:
230 if( nPart == ControlPart::Entire )
231 return true;
232 break;
233 case ControlType::Frame:
234 if( nPart == ControlPart::Border )
235 return true;
236 break;
237 case ControlType::ListNet:
238 if( nPart == ControlPart::Entire )
239 return true;
240 break;
241 default: break;
244 return false;
247 bool AquaSalGraphics::hitTestNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion,
248 const Point& rPos, bool& rIsInside )
250 if ( nType == ControlType::Scrollbar )
252 tools::Rectangle aRect;
253 bool bValid = AquaGetScrollRect( /* TODO: m_nScreen */ nPart, rControlRegion, aRect );
254 rIsInside = bValid && aRect.IsInside( rPos );
255 return bValid;
256 } // ControlType::Scrollbar
258 return false;
262 kThemeStateInactive = 0,
263 kThemeStateActive = 1,
264 kThemeStatePressed = 2,
265 kThemeStateRollover = 6,
266 kThemeStateUnavailable = 7,
267 kThemeStateUnavailableInactive = 8
268 kThemeStatePressedUp = 2,
269 kThemeStatePressedDown = 3
271 UInt32 AquaSalGraphics::getState( ControlState nState )
273 const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
274 if( !(nState & ControlState::ENABLED) || ! bDrawActive )
276 return kThemeStateInactive;
279 if( nState & ControlState::PRESSED )
280 return kThemeStatePressed;
282 return kThemeStateActive;
285 UInt32 AquaSalGraphics::getTrackState( ControlState nState )
287 const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
288 if( ! (nState & ControlState::ENABLED) || ! bDrawActive )
289 return kThemeTrackInactive;
291 return kThemeTrackActive;
294 bool AquaSalGraphics::drawNativeControl(ControlType nType,
295 ControlPart nPart,
296 const tools::Rectangle& rControlRegion,
297 ControlState nState,
298 const ImplControlValue& aValue,
299 const OUString& )
301 bool bOK = false;
303 if( ! CheckContext() )
304 return false;
306 maContextHolder.saveState();
308 tools::Rectangle buttonRect = rControlRegion;
309 HIRect rc = ImplGetHIRectFromRectangle(buttonRect);
311 switch( nType )
314 case ControlType::Combobox:
315 if ( nPart == ControlPart::HasBackgroundTexture ||
316 nPart == ControlPart::Entire )
318 HIThemeButtonDrawInfo aComboInfo;
319 aComboInfo.version = 0;
320 aComboInfo.kind = kThemeComboBox;
321 aComboInfo.state = getState( nState );
322 aComboInfo.value = kThemeButtonOn;
323 aComboInfo.adornment = kThemeAdornmentNone;
325 if( nState & ControlState::FOCUSED )
326 aComboInfo.adornment |= kThemeAdornmentFocus;
328 HIThemeDrawButton(&rc, &aComboInfo, maContextHolder.get(), kHIThemeOrientationNormal,&rc);
329 bOK = true;
331 break;
333 case ControlType::Toolbar:
335 #if HAVE_FEATURE_MACOSX_SANDBOX
336 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
337 aMenuItemDrawInfo.version = 0;
338 aMenuItemDrawInfo.state = kThemeMenuActive;
339 aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
340 HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,maContextHolder.get(),kHIThemeOrientationNormal,NULL);
341 #else
342 if (rControlRegion.Top() == 0 && nPart == ControlPart::DrawBackgroundHorz)
344 const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
345 CGFloat unifiedHeight = rControlRegion.GetHeight();
346 CGRect drawRect = CGRectMake(rControlRegion.Left(), rControlRegion.Top(), rControlRegion.GetWidth(), rControlRegion.GetHeight());
347 CUIDraw([NSWindow coreUIRenderer], drawRect, maContextHolder.get(),
348 reinterpret_cast<CFDictionaryRef>([NSDictionary dictionaryWithObjectsAndKeys:
349 @"kCUIWidgetWindowFrame", @"widget",
350 @"regularwin", @"windowtype",
351 (bDrawActive ? @"normal" : @"inactive"), @"state",
352 [NSNumber numberWithDouble:unifiedHeight], @"kCUIWindowFrameUnifiedTitleBarHeightKey",
353 [NSNumber numberWithBool:NO], @"kCUIWindowFrameDrawTitleSeparatorKey",
354 [NSNumber numberWithBool:YES], @"is.flipped",
355 nil]),
356 nil);
358 else
360 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
361 aMenuItemDrawInfo.version = 0;
362 aMenuItemDrawInfo.state = kThemeMenuActive;
363 aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
364 HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
366 #endif
367 bOK = true;
369 break;
371 case ControlType::WindowBackground:
373 HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
374 aThemeBackgroundInfo.version = 0;
375 aThemeBackgroundInfo.state = getState( nState );
376 aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundActive;
377 // FIXME: without this magical offset there is a 2 pixel black border on the right and bottom
378 rc.size.width += 2;
379 rc.size.height += 2;
381 HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, maContextHolder.get(), kHIThemeOrientationNormal);
382 CGContextFillRect( maContextHolder.get(), rc );
383 bOK = true;
385 break;
387 case ControlType::Tooltip:
389 HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
390 aThemeBackgroundInfo.version = 0;
391 aThemeBackgroundInfo.state = getState( nState );
392 aThemeBackgroundInfo.kind = kThemeBrushAlertBackgroundActive;
393 rc.size.width += 2;
394 rc.size.height += 2;
396 HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, maContextHolder.get(), kHIThemeOrientationNormal);
397 CGContextFillRect( maContextHolder.get(), rc );
398 bOK = true;
400 break;
402 case ControlType::Menubar:
403 case ControlType::MenuPopup:
405 if ((nPart == ControlPart::Entire) || (nPart == ControlPart::MenuItem )|| (nPart == ControlPart::HasBackgroundTexture ))
407 // FIXME: without this magical offset there is a 2 pixel black border on the right
408 rc.size.width += 2;
410 HIThemeMenuDrawInfo aMenuInfo;
411 aMenuInfo.version = 0;
412 aMenuInfo.menuType = kThemeMenuTypePullDown;
414 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
415 // the Aqua grey theme when the item is selected is drawn here.
416 aMenuItemDrawInfo.itemType = kThemeMenuItemPlain;
418 if ((nPart == ControlPart::MenuItem ) && (nState & ControlState::SELECTED))
420 // the blue theme when the item is selected is drawn here.
421 aMenuItemDrawInfo.state = kThemeMenuSelected;
423 else
425 // normal color for non selected item
426 aMenuItemDrawInfo.state = kThemeMenuActive;
429 // repaints the background of the pull down menu
430 HIThemeDrawMenuBackground(&rc,&aMenuInfo,maContextHolder.get(),kHIThemeOrientationNormal);
432 // repaints the item either blue (selected) and/or Aqua grey (active only)
433 HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,maContextHolder.get(),kHIThemeOrientationNormal,&rc);
435 bOK = true;
437 else if(( nPart == ControlPart::MenuItemCheckMark )||( nPart == ControlPart::MenuItemRadioMark )) {
438 if( nState & ControlState::PRESSED ) {//checked, else it is not displayed (see vcl/source/window/menu.cxx)
439 HIThemeTextInfo aTextInfo;
440 aTextInfo.version = 0;
441 aTextInfo.state = (nState & ControlState::ENABLED) ? kThemeStateInactive: kThemeStateActive;
442 aTextInfo.fontID = kThemeMenuItemMarkFont;
443 aTextInfo.horizontalFlushness=kHIThemeTextHorizontalFlushCenter;
444 aTextInfo.verticalFlushness=kHIThemeTextVerticalFlushTop;
445 aTextInfo.options=kHIThemeTextBoxOptionNone;
446 aTextInfo.truncationPosition=kHIThemeTextTruncationNone;
447 //aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone
449 if( nState & ControlState::SELECTED) aTextInfo.state = kThemeStatePressed; //item highlighted
451 UniChar mark=( nPart == ControlPart::MenuItemCheckMark ) ? kCheckUnicode: kBulletUnicode;//0x2713;
452 CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull);
453 HIThemeDrawTextBox(cfString, &rc, &aTextInfo, maContextHolder.get(), kHIThemeOrientationNormal);
454 if (cfString)
455 CFRelease(cfString);
457 bOK = true;
461 break;
463 case ControlType::Pushbutton:
465 // [ FIXME] : instead of use a value, vcl can retrieve correct values on the fly (to be implemented)
466 const int PB_Mini_Height = 15;
467 const int PB_Norm_Height = 21;
469 HIThemeButtonDrawInfo aPushInfo;
470 aPushInfo.version = 0;
472 // no animation
473 aPushInfo.animation.time.start = 0;
474 aPushInfo.animation.time.current = 0;
475 PushButtonValue const * pPBVal = aValue.getType() == ControlType::Pushbutton ? static_cast<PushButtonValue const *>(&aValue) : nullptr;
476 int nPaintHeight = static_cast<int>(rc.size.height);
478 if( pPBVal && pPBVal->mbBevelButton )
480 aPushInfo.kind = kThemeRoundedBevelButton;
482 else if( rc.size.height <= PB_Norm_Height )
484 aPushInfo.kind = kThemePushButtonMini;
485 nPaintHeight = PB_Mini_Height;
487 else if( (pPBVal && pPBVal->mbSingleLine) || rc.size.height < (PB_Norm_Height + PB_Norm_Height/2) )
489 aPushInfo.kind = kThemePushButtonNormal;
490 nPaintHeight = PB_Norm_Height;
492 // avoid clipping when focused
493 rc.origin.x += FOCUS_RING_WIDTH/2;
494 rc.size.width -= FOCUS_RING_WIDTH;
496 else
497 aPushInfo.kind = kThemeBevelButton;
499 // translate the origin for controls with fixed paint height
500 // so content ends up somewhere sensible
501 int delta_y = static_cast<int>(rc.size.height) - nPaintHeight;
502 rc.origin.y += delta_y/2;
504 aPushInfo.state = getState( nState );
505 aPushInfo.value = ImplGetButtonValue( aValue.getTristateVal() );
507 aPushInfo.adornment = ( nState & ControlState::DEFAULT ) ?
508 kThemeAdornmentDefault :
509 kThemeAdornmentNone;
510 if( nState & ControlState::FOCUSED )
511 aPushInfo.adornment |= kThemeAdornmentFocus;
513 HIThemeDrawButton( &rc, &aPushInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr );
514 bOK = true;
516 break;
518 case ControlType::Radiobutton:
519 case ControlType::Checkbox:
521 HIThemeButtonDrawInfo aInfo;
522 aInfo.version = 0;
523 switch( nType )
525 case ControlType::Radiobutton: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeRadioButton;
526 else aInfo.kind = kThemeSmallRadioButton;
527 break;
528 case ControlType::Checkbox: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeCheckBox;
529 else aInfo.kind = kThemeSmallCheckBox;
530 break;
531 default: break;
534 aInfo.state = getState( nState );
536 ButtonValue aButtonValue = aValue.getTristateVal();
537 aInfo.value = ImplGetButtonValue( aButtonValue );
539 aInfo.adornment = ( nState & ControlState::DEFAULT ) ?
540 kThemeAdornmentDefault :
541 kThemeAdornmentNone;
542 if( nState & ControlState::FOCUSED )
543 aInfo.adornment |= kThemeAdornmentFocus;
544 HIThemeDrawButton( &rc, &aInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr );
545 bOK = true;
547 break;
549 case ControlType::ListNode:
551 ButtonValue aButtonValue = aValue.getTristateVal();
553 if( AllSettings::GetLayoutRTL() && aButtonValue == ButtonValue::Off )
555 // FIXME: a value of kThemeDisclosureLeft
556 // should draw a theme compliant left disclosure triangle
557 // sadly this does not seem to work, so we'll draw a left
558 // grey equilateral triangle here ourselves.
559 // Perhaps some other HIThemeButtonDrawInfo setting would do the trick ?
561 CGContextSetShouldAntialias( maContextHolder.get(), true );
562 CGFloat const aGrey[] = { 0.45, 0.45, 0.45, 1.0 };
563 CGContextSetFillColor( maContextHolder.get(), aGrey );
564 CGContextBeginPath( maContextHolder.get() );
565 float x = rc.origin.x + rc.size.width;
566 float y = rc.origin.y;
567 CGContextMoveToPoint( maContextHolder.get(), x, y );
568 y += rc.size.height;
569 CGContextAddLineToPoint( maContextHolder.get(), x, y );
570 x -= rc.size.height * 0.866; // cos( 30 degree ) is approx. 0.866
571 y -= rc.size.height/2;
572 CGContextAddLineToPoint( maContextHolder.get(), x, y );
573 CGContextDrawPath( maContextHolder.get(), kCGPathEOFill );
575 else
577 HIThemeButtonDrawInfo aInfo;
578 aInfo.version = 0;
579 aInfo.kind = kThemeDisclosureTriangle;
580 aInfo.value = kThemeDisclosureRight;
581 aInfo.state = getState( nState );
583 aInfo.adornment = kThemeAdornmentNone;
585 switch( aButtonValue ) {
586 case ButtonValue::On: aInfo.value = kThemeDisclosureDown;//expanded
587 break;
588 case ButtonValue::Off:
589 // FIXME: this should have drawn a theme compliant disclosure triangle
590 // (see above)
591 if( AllSettings::GetLayoutRTL() )
593 aInfo.value = kThemeDisclosureLeft;//collapsed, RTL
595 break;
596 case ButtonValue::DontKnow: //what to do?
597 default:
598 break;
601 HIThemeDrawButton( &rc, &aInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr );
603 bOK = true;
605 break;
607 case ControlType::Progress:
608 case ControlType::IntroProgress:
610 long nProgressWidth = aValue.getNumericVal();
611 HIThemeTrackDrawInfo aTrackInfo;
612 aTrackInfo.version = 0;
613 aTrackInfo.kind = (rc.size.height > 10) ? kThemeProgressBarLarge : kThemeProgressBarMedium;
614 aTrackInfo.bounds = rc;
615 aTrackInfo.min = 0;
616 aTrackInfo.max = static_cast<SInt32>(rc.size.width);
617 aTrackInfo.value = nProgressWidth;
618 aTrackInfo.reserved = 0;
619 aTrackInfo.bounds.origin.y -= 2; // FIXME: magic for shadow
620 aTrackInfo.bounds.size.width -= 2; // FIXME: magic for shadow
621 aTrackInfo.attributes = kThemeTrackHorizontal;
622 if( AllSettings::GetLayoutRTL() )
623 aTrackInfo.attributes |= kThemeTrackRightToLeft;
624 aTrackInfo.enableState = getTrackState( nState );
625 // the intro bitmap never gets key anyway; we want to draw that enabled
626 if( nType == ControlType::IntroProgress )
627 aTrackInfo.enableState = kThemeTrackActive;
628 aTrackInfo.filler1 = 0;
629 aTrackInfo.trackInfo.progress.phase = static_cast<long long>(CFAbsoluteTimeGetCurrent()*10.0);
631 HIThemeDrawTrack( &aTrackInfo, nullptr, maContextHolder.get(), kHIThemeOrientationNormal );
632 bOK = true;
634 break;
636 case ControlType::Slider:
638 SliderValue const * pSLVal = static_cast<SliderValue const *>(&aValue);
640 HIThemeTrackDrawInfo aTrackDraw;
641 aTrackDraw.kind = kThemeSliderMedium;
642 if( nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea )
644 aTrackDraw.bounds = rc;
645 aTrackDraw.min = pSLVal->mnMin;
646 aTrackDraw.max = pSLVal->mnMax;
647 aTrackDraw.value = pSLVal->mnCur;
648 aTrackDraw.reserved = 0;
649 aTrackDraw.attributes = kThemeTrackShowThumb;
650 if( nPart == ControlPart::TrackHorzArea )
651 aTrackDraw.attributes |= kThemeTrackHorizontal;
652 aTrackDraw.enableState = (nState & ControlState::ENABLED)
653 ? kThemeTrackActive : kThemeTrackInactive;
655 SliderTrackInfo aSlideInfo;
656 aSlideInfo.thumbDir = kThemeThumbUpward;
657 aSlideInfo.pressState = 0;
658 aTrackDraw.trackInfo.slider = aSlideInfo;
660 HIThemeDrawTrack( &aTrackDraw, nullptr, maContextHolder.get(), kHIThemeOrientationNormal );
661 bOK = true;
664 break;
666 case ControlType::Scrollbar:
668 const ScrollbarValue* pScrollbarVal = (aValue.getType() == ControlType::Scrollbar) ? static_cast<const ScrollbarValue*>(&aValue) : nullptr;
670 if( nPart == ControlPart::DrawBackgroundVert ||
671 nPart == ControlPart::DrawBackgroundHorz )
673 HIThemeTrackDrawInfo aTrackDraw;
674 aTrackDraw.kind = kThemeMediumScrollBar;
675 // FIXME: the scrollbar length must be adjusted
676 if (nPart == ControlPart::DrawBackgroundVert)
677 rc.size.height += 2;
678 else
679 rc.size.width += 2;
681 aTrackDraw.bounds = rc;
682 aTrackDraw.min = pScrollbarVal->mnMin;
683 aTrackDraw.max = pScrollbarVal->mnMax - pScrollbarVal->mnVisibleSize;
684 aTrackDraw.value = pScrollbarVal->mnCur;
685 aTrackDraw.reserved = 0;
686 aTrackDraw.attributes = kThemeTrackShowThumb;
687 if( nPart == ControlPart::DrawBackgroundHorz )
688 aTrackDraw.attributes |= kThemeTrackHorizontal;
689 aTrackDraw.enableState = getTrackState( nState );
691 ScrollBarTrackInfo aScrollInfo;
692 aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize;
693 aScrollInfo.pressState = 0;
695 if ( pScrollbarVal->mnButton1State & ControlState::ENABLED )
697 if ( pScrollbarVal->mnButton1State & ControlState::PRESSED )
698 aScrollInfo.pressState = kThemeTopOutsideArrowPressed;
701 if ( pScrollbarVal->mnButton2State & ControlState::ENABLED )
703 if ( pScrollbarVal->mnButton2State & ControlState::PRESSED )
704 aScrollInfo.pressState = kThemeBottomOutsideArrowPressed;
707 if ( pScrollbarVal->mnThumbState & ControlState::ENABLED )
709 if ( pScrollbarVal->mnThumbState & ControlState::PRESSED )
710 aScrollInfo.pressState = kThemeThumbPressed;
713 aTrackDraw.trackInfo.scrollbar = aScrollInfo;
715 HIThemeDrawTrack( &aTrackDraw, nullptr, maContextHolder.get(), kHIThemeOrientationNormal );
716 bOK = true;
719 break;
721 case ControlType::TabPane:
723 HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
724 aTabPaneDrawInfo.version = 1;
725 aTabPaneDrawInfo.state = kThemeStateActive;
726 aTabPaneDrawInfo.direction=kThemeTabNorth;
727 aTabPaneDrawInfo.size=kHIThemeTabSizeNormal;
728 aTabPaneDrawInfo.kind=kHIThemeTabKindNormal;
730 //the border is outside the rect rc for Carbon
731 //but for VCL it should be inside
732 rc.origin.x+=1;
733 rc.origin.y-=TAB_HEIGHT_NORMAL/2;
734 rc.size.height+=TAB_HEIGHT_NORMAL/2;
735 rc.size.width-=2;
737 HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
739 bOK = true;
741 break;
743 case ControlType::TabItem:
745 HIThemeTabDrawInfo aTabItemDrawInfo;
746 aTabItemDrawInfo.version=1;
747 aTabItemDrawInfo.style=kThemeTabNonFront;
748 aTabItemDrawInfo.direction=kThemeTabNorth;
749 aTabItemDrawInfo.size=kHIThemeTabSizeNormal;
750 aTabItemDrawInfo.adornment=kHIThemeTabAdornmentTrailingSeparator;
751 //State
752 if(nState & ControlState::SELECTED) {
753 aTabItemDrawInfo.style=kThemeTabFront;
755 if(nState & ControlState::FOCUSED) {
756 aTabItemDrawInfo.adornment|=kHIThemeTabAdornmentFocus;
759 //first, last or middle tab
760 aTabItemDrawInfo.position=kHIThemeTabPositionMiddle;
762 TabitemValue const * pTabValue = static_cast<TabitemValue const *>(&aValue);
763 TabitemFlags nAlignment = pTabValue->mnAlignment;
764 //TabitemFlags::LeftAligned (and TabitemFlags::RightAligned) for the leftmost (or rightmost) tab
765 //when there are several lines of tabs because there is only one first tab and one
766 //last tab and TabitemFlags::FirstInGroup (and TabitemFlags::LastInGroup) because when the
767 //line width is different from window width, there may not be TabitemFlags::RightAligned
768 if( ( (nAlignment & TabitemFlags::LeftAligned)&&(nAlignment & TabitemFlags::RightAligned) ) ||
769 ( (nAlignment & TabitemFlags::FirstInGroup)&&(nAlignment & TabitemFlags::LastInGroup) )
770 ) //tab alone
771 aTabItemDrawInfo.position=kHIThemeTabPositionOnly;
772 else if((nAlignment & TabitemFlags::LeftAligned)||(nAlignment & TabitemFlags::FirstInGroup))
773 aTabItemDrawInfo.position=kHIThemeTabPositionFirst;
774 else if((nAlignment & TabitemFlags::RightAligned)||(nAlignment & TabitemFlags::LastInGroup))
775 aTabItemDrawInfo.position=kHIThemeTabPositionLast;
777 //support for RTL
778 //see issue 79748
779 if( AllSettings::GetLayoutRTL() ) {
780 if( aTabItemDrawInfo.position == kHIThemeTabPositionFirst )
781 aTabItemDrawInfo.position = kHIThemeTabPositionLast;
782 else if( aTabItemDrawInfo.position == kHIThemeTabPositionLast )
783 aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
786 rc.size.width+=2;//because VCL has 2 empty pixels between 2 tabs
787 rc.origin.x-=1;
789 HIThemeDrawTab(&rc, &aTabItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, &rc );
791 bOK=true;
793 break;
795 case ControlType::Listbox:
796 switch( nPart)
798 case ControlPart::Entire:
799 case ControlPart::ButtonDown:
801 HIThemeButtonDrawInfo aListInfo;
802 aListInfo.version = 0;
803 aListInfo.kind = kThemePopupButton;
804 aListInfo.state = getState( nState );//kThemeStateInactive -> greyed
805 aListInfo.value = kThemeButtonOn;
807 aListInfo.adornment = kThemeAdornmentDefault;
808 if( nState & ControlState::FOCUSED )
809 aListInfo.adornment |= kThemeAdornmentFocus;
811 HIThemeDrawButton(&rc, &aListInfo, maContextHolder.get(), kHIThemeOrientationNormal,&rc);
812 bOK = true;
813 break;
815 case ControlPart::ListboxWindow:
817 HIThemeFrameDrawInfo aTextDrawInfo;
818 aTextDrawInfo.version=0;
819 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
820 aTextDrawInfo.state=getState( nState );
821 aTextDrawInfo.isFocused=false;
823 rc.size.width+=1; // else there's a white space because a macOS theme has no 3D border
824 rc.size.height+=1;
825 HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
827 if(nState & ControlState::FOCUSED) HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal);
829 bOK=true;
830 break;
832 default: break;
834 break;
836 case ControlType::Editbox:
837 case ControlType::MultilineEditbox:
839 HIThemeFrameDrawInfo aTextDrawInfo;
840 aTextDrawInfo.version=0;
841 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
842 aTextDrawInfo.state=getState( nState );
843 aTextDrawInfo.isFocused=false;
845 rc.size.width += 1; // else there may be a white space because a macOS theme has no 3D border
846 // change rc so that the frame will encompass only the content region
847 // see counterpart in GetNativeControlRegion
848 rc.size.width += 2;
849 rc.size.height += 2;
851 //CGContextSetFillColorWithColor
852 CGContextFillRect (maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
853 //fill a white background, because drawFrame only draws the border
855 HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
857 if(nState & ControlState::FOCUSED) HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal);
859 bOK=true;
861 break;
863 case ControlType::Spinbox:
865 if(nPart == ControlPart::Entire)
867 //text field:
868 HIThemeFrameDrawInfo aTextDrawInfo;
869 aTextDrawInfo.version=0;
870 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
871 aTextDrawInfo.state=getState( nState );
872 aTextDrawInfo.isFocused=false;
874 //rc.size.width contains the full size of the spinbox ie textfield + button
875 //so we remove the button width and the space between the button and the textfield
876 rc.size.width -= SPIN_BUTTON_SPACE + SPIN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
877 rc.origin.x += FOCUS_RING_WIDTH;
878 rc.origin.y += FOCUS_RING_WIDTH;
880 //CGContextSetFillColorWithColor
881 CGContextFillRect (maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
882 //fill a white background, because drawFrame only draws the border
884 HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
886 if(nState & ControlState::FOCUSED) HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal);
888 //buttons:
889 const SpinbuttonValue* pSpinButtonVal = (aValue.getType() == ControlType::SpinButtons) ? static_cast<const SpinbuttonValue*>(&aValue) : nullptr;
890 ControlState nUpperState = ControlState::ENABLED;//state of the upper button
891 ControlState nLowerState = ControlState::ENABLED;//and of the lower button
892 if(pSpinButtonVal) {//pSpinButtonVal is sometimes null
893 nUpperState = pSpinButtonVal->mnUpperState;
894 nLowerState = pSpinButtonVal->mnLowerState;
896 HIThemeButtonDrawInfo aSpinInfo;
897 aSpinInfo.kind = kThemeIncDecButton;
898 aSpinInfo.state = kThemeStateActive;
899 if(nUpperState & ControlState::PRESSED)
900 aSpinInfo.state = kThemeStatePressedUp;
901 else if(nLowerState & ControlState::PRESSED)
902 aSpinInfo.state = kThemeStatePressedDown;
903 else if((nUpperState & ~ControlState::ENABLED)||(nLowerState & ~ControlState::ENABLED))
904 aSpinInfo.state = kThemeStateInactive;
905 else if((nUpperState & ControlState::ROLLOVER)||(nLowerState & ControlState::ROLLOVER))
906 aSpinInfo.state = kThemeStateRollover;
908 tools::Rectangle aSpinRect( pSpinButtonVal->maUpperRect );
909 aSpinRect.Union( pSpinButtonVal->maLowerRect );
910 HIRect buttonRc = ImplGetHIRectFromRectangle(aSpinRect);
912 // FIXME: without this fuzz factor there is some unwanted clipping
913 if( AllSettings::GetLayoutRTL() )
914 buttonRc.origin.x -= FOCUS_RING_WIDTH - CLIP_FUZZ;
915 else
916 buttonRc.origin.x += FOCUS_RING_WIDTH + CLIP_FUZZ;
918 switch( aValue.getTristateVal() )
920 case ButtonValue::On: aSpinInfo.value = kThemeButtonOn;
921 break;
922 case ButtonValue::Off: aSpinInfo.value = kThemeButtonOff;
923 break;
924 case ButtonValue::Mixed:
925 case ButtonValue::DontKnow:
926 default: aSpinInfo.value = kThemeButtonMixed;
927 break;
930 aSpinInfo.adornment = ( (nUpperState & ControlState::DEFAULT) ||
931 (nLowerState & ControlState::DEFAULT) ) ?
932 kThemeAdornmentDefault :
933 kThemeAdornmentNone;
934 if( (nUpperState & ControlState::FOCUSED) || (nLowerState & ControlState::FOCUSED))
935 aSpinInfo.adornment |= kThemeAdornmentFocus;
937 HIThemeDrawButton( &buttonRc, &aSpinInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr );
940 bOK=true;
944 break;
946 case ControlType::Frame:
948 DrawFrameFlags nStyle = static_cast<DrawFrameFlags>(aValue.getNumericVal());
949 if( nPart == ControlPart::Border ) {
950 if(!( nStyle & DrawFrameFlags::Menu ) && !(nStyle & DrawFrameFlags::WindowBorder) )
952 // #i84756# strange effects start to happen when HIThemeDrawFrame
953 // meets the border of the window. These can be avoided by clipping
954 // to the boundary of the frame
955 if( rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight-3 )
957 CGMutablePathRef rPath = CGPathCreateMutable();
958 CGPathAddRect( rPath, nullptr, CGRectMake( 0, 0, mpFrame->maGeometry.nWidth-1, mpFrame->maGeometry.nHeight-1 ) );
960 CGContextBeginPath( maContextHolder.get() );
961 CGContextAddPath( maContextHolder.get(), rPath );
962 CGContextClip( maContextHolder.get() );
963 CGPathRelease( rPath );
966 HIThemeFrameDrawInfo aTextDrawInfo;
967 aTextDrawInfo.version=0;
968 aTextDrawInfo.kind=kHIThemeFrameListBox;
969 aTextDrawInfo.state=kThemeStateActive;
970 aTextDrawInfo.isFocused=false;
972 HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
974 bOK=true;
978 break;
980 case ControlType::ListNet:
982 //do nothing as there isn't net for listviews on macos
983 bOK=true;
985 break;
986 default: break;
989 maContextHolder.restoreState();
991 /* #i90291# in most cases invalidating the whole control region instead
992 of just the unclipped part of it is sufficient (and probably faster).
993 However for the window background we should not unnecessarily enlarge
994 the really changed rectangle since the difference is usually quite high
995 (the background is always drawn as a whole since we don't know anything
996 about its possible contents)
998 if( nType == ControlType::WindowBackground )
1000 CGRect aRect = { { 0, 0 }, { 0, 0 } };
1001 if( mxClipPath )
1002 aRect = CGPathGetBoundingBox( mxClipPath );
1003 if( aRect.size.width != 0 && aRect.size.height != 0 )
1004 buttonRect.Intersection( tools::Rectangle( Point( static_cast<long int>(aRect.origin.x),
1005 static_cast<long int>(aRect.origin.y) ),
1006 Size( static_cast<long int>(aRect.size.width),
1007 static_cast<long int>(aRect.size.height) ) ) );
1010 RefreshRect( buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight() );
1012 return bOK;
1015 bool AquaSalGraphics::getNativeControlRegion( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, ControlState /*nState*/,
1016 const ImplControlValue& aValue, const OUString&,
1017 tools::Rectangle &rNativeBoundingRegion, tools::Rectangle &rNativeContentRegion )
1020 bool toReturn = false;
1022 tools::Rectangle aCtrlBoundRect( rControlRegion );
1023 short x = aCtrlBoundRect.Left();
1024 short y = aCtrlBoundRect.Top();
1025 short w, h;
1027 sal_uInt8 nBorderCleanup = 0;
1029 switch (nType)
1031 case ControlType::Slider:
1033 if( nPart == ControlPart::ThumbHorz )
1035 w = 19; // taken from HIG
1036 h = aCtrlBoundRect.GetHeight();
1037 rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1038 toReturn = true;
1040 else if( nPart == ControlPart::ThumbVert )
1042 w = aCtrlBoundRect.GetWidth();
1043 h = 18; // taken from HIG
1044 rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1045 toReturn = true;
1048 break;
1050 case ControlType::Scrollbar:
1052 tools::Rectangle aRect;
1053 if( AquaGetScrollRect( /* m_nScreen */ nPart, aCtrlBoundRect, aRect ) )
1055 toReturn = true;
1056 rNativeBoundingRegion = aRect;
1057 rNativeContentRegion = aRect;
1060 break;
1062 case ControlType::Pushbutton:
1063 case ControlType::Radiobutton:
1064 case ControlType::Checkbox:
1066 if ( nType == ControlType::Pushbutton )
1068 w = aCtrlBoundRect.GetWidth();
1069 h = aCtrlBoundRect.GetHeight();
1071 else
1073 // checkbox and radio borders need cleanup after unchecking them
1074 nBorderCleanup = 4;
1076 // TEXT_SEPARATOR to respect Aqua HIG
1077 w = BUTTON_WIDTH + TEXT_SEPARATOR;
1078 h = BUTTON_HEIGHT;
1082 rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h + nBorderCleanup) );
1083 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1085 toReturn = true;
1087 break;
1088 case ControlType::Progress:
1090 tools::Rectangle aRect( aCtrlBoundRect );
1091 if( aRect.GetHeight() < 16 )
1092 aRect.SetBottom( aRect.Top() + 9 ); // values taken from HIG for medium progress
1093 else
1094 aRect.SetBottom( aRect.Top() + 15 ); // values taken from HIG for large progress
1095 rNativeBoundingRegion = aRect;
1096 rNativeContentRegion = aRect;
1097 toReturn = true;
1099 break;
1101 case ControlType::IntroProgress:
1103 tools::Rectangle aRect( aCtrlBoundRect );
1104 aRect.SetBottom( aRect.Top() + INTRO_PROGRESS_HEIGHT ); // values taken from HIG for medium progress
1105 rNativeBoundingRegion = aRect;
1106 rNativeContentRegion = aRect;
1107 toReturn = true;
1109 break;
1111 case ControlType::TabItem:
1113 w = aCtrlBoundRect.GetWidth() + 2*TAB_TEXT_OFFSET - 2*VCL_TAB_TEXT_OFFSET;
1114 h = TAB_HEIGHT_NORMAL+2;
1116 rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1117 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1119 toReturn = true;
1121 break;
1123 case ControlType::Editbox:
1125 w = aCtrlBoundRect.GetWidth();
1126 if( w < 3+2*FOCUS_RING_WIDTH )
1127 w = 3+2*FOCUS_RING_WIDTH;
1128 h = TEXT_EDIT_HEIGHT_NORMAL+2*FOCUS_RING_WIDTH;
1129 if( h < aCtrlBoundRect.GetHeight() )
1130 h = aCtrlBoundRect.GetHeight();
1132 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) ) );
1133 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1135 toReturn = true;
1137 break;
1138 case ControlType::Listbox:
1139 case ControlType::Combobox:
1141 if( nPart == ControlPart::Entire )
1143 w = aCtrlBoundRect.GetWidth();
1144 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
1146 rNativeContentRegion = tools::Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*FOCUS_RING_WIDTH, h ) );
1147 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1149 toReturn = true;
1151 else if( nPart == ControlPart::ButtonDown )
1153 w = aCtrlBoundRect.GetWidth();
1154 if( w < 3+2*FOCUS_RING_WIDTH )
1155 w = 3+2*FOCUS_RING_WIDTH;
1156 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
1158 x += w-DROPDOWN_BUTTON_WIDTH - FOCUS_RING_WIDTH;
1159 y += FOCUS_RING_WIDTH;
1160 w = DROPDOWN_BUTTON_WIDTH;
1162 rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1163 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
1165 toReturn = true;
1167 else if( nPart == ControlPart::SubEdit )
1169 w = aCtrlBoundRect.GetWidth();
1170 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
1172 x += FOCUS_RING_WIDTH;
1173 x += 3; // add an offset for rounded borders
1174 y += 2; // don't draw into upper border
1175 y += FOCUS_RING_WIDTH;
1176 w -= 3 + DROPDOWN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
1177 if( nType == ControlType::Listbox )
1178 w -= 9; // HIG specifies 9 units distance between dropdown button area and content
1179 h -= 4; // don't draw into lower border
1181 rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1182 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
1184 toReturn = true;
1187 break;
1188 case ControlType::Spinbox:
1189 if( nPart == ControlPart::Entire ) {
1190 w = aCtrlBoundRect.GetWidth();
1191 if( w < 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH )
1192 w = 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH;
1193 h = TEXT_EDIT_HEIGHT_NORMAL;
1195 rNativeContentRegion = tools::Rectangle( Point( x+FOCUS_RING_WIDTH, y ), Size( w-2*FOCUS_RING_WIDTH, h ) );
1196 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1198 toReturn = true;
1200 else if( nPart == ControlPart::SubEdit ) {
1201 w = aCtrlBoundRect.GetWidth() - SPIN_BUTTON_SPACE - SPIN_BUTTON_WIDTH;
1202 h = TEXT_EDIT_HEIGHT_NORMAL;
1203 x += 4; // add an offset for rounded borders
1204 y += 2; // don't draw into upper border
1205 w -= 8; // offset for left and right rounded border
1206 h -= 4; // don't draw into upper or lower border
1208 rNativeContentRegion = tools::Rectangle( Point( x + FOCUS_RING_WIDTH, y + FOCUS_RING_WIDTH ), Size( w - 2* FOCUS_RING_WIDTH, h ) );
1209 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1211 toReturn = true;
1213 else if( nPart == ControlPart::ButtonUp ) {
1214 //aCtrlBoundRect.GetWidth() contains the width of the full control
1215 //ie the width of the textfield + button
1216 //x is the position of the left corner of the full control
1217 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
1218 y += FOCUS_RING_WIDTH - CLIP_FUZZ;
1219 w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
1220 h = SPIN_UPPER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
1222 rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1223 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1225 toReturn = true;
1227 else if( nPart == ControlPart::ButtonDown ) {
1228 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
1229 y += SPIN_UPPER_BUTTON_HEIGHT + FOCUS_RING_WIDTH - CLIP_FUZZ;
1230 w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
1231 h = SPIN_LOWER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
1233 rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1234 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1236 toReturn = true;
1238 break;
1239 case ControlType::Frame:
1241 DrawFrameStyle nStyle = static_cast<DrawFrameStyle>(aValue.getNumericVal() & 0x000f);
1242 DrawFrameFlags nFlags = static_cast<DrawFrameFlags>(aValue.getNumericVal() & 0xfff0);
1243 if( ( nPart == ControlPart::Border ) &&
1244 !( nFlags & (DrawFrameFlags::Menu | DrawFrameFlags::WindowBorder | DrawFrameFlags::BorderWindowBorder) ) )
1246 tools::Rectangle aRect(aCtrlBoundRect);
1247 if( nStyle == DrawFrameStyle::DoubleIn )
1249 aRect.AdjustLeft(1);
1250 aRect.AdjustTop(1);
1251 //rRect.Right() -= 1;
1252 //rRect.Bottom() -= 1;
1254 else
1256 aRect.AdjustLeft(1);
1257 aRect.AdjustTop(1);
1258 aRect.AdjustRight(-1);
1259 aRect.AdjustBottom(-1);
1262 rNativeContentRegion = aRect;
1263 rNativeBoundingRegion = aRect;
1265 toReturn = true;
1268 break;
1270 case ControlType::Menubar:
1271 case ControlType::MenuPopup:
1273 if(( nPart == ControlPart::MenuItemCheckMark )||( nPart == ControlPart::MenuItemRadioMark )) {
1275 w=10;
1276 h=10;//dimensions of the mark (10px font)
1278 rNativeContentRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1279 rNativeBoundingRegion = tools::Rectangle( Point( x, y ), Size( w, h ) );
1281 toReturn = true;
1284 break;
1285 default: break;
1289 return toReturn;
1292 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */