Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / osx / salnativewidgets.cxx
blob5aa6f8d097e8a0e1afd6f75960b07384d60894f9
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 Rectangle maInvalidateRect;
52 AquaBlinker( AquaSalFrame* pFrame, const Rectangle& rRect )
53 : mpFrame( pFrame ), maInvalidateRect( rRect )
55 mpFrame->maBlinkers.push_back( this );
58 public:
60 static void Blink( AquaSalFrame*, const Rectangle&, int nTimeout = 80 );
62 virtual void Invoke() SAL_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 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(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 Rectangle& rControlRect, Rectangle& rResultRect )
123 bool bRetVal = true;
124 rResultRect = rControlRect;
126 switch( nPart )
128 case PART_BUTTON_UP:
129 rResultRect.Bottom() = rResultRect.Top();
130 break;
132 case PART_BUTTON_DOWN:
133 rResultRect.Top() = rResultRect.Bottom();
134 break;
136 case PART_BUTTON_LEFT:
137 rResultRect.Right() = rResultRect.Left();
138 break;
140 case PART_BUTTON_RIGHT:
141 rResultRect.Left() = rResultRect.Right();
142 break;
144 case PART_TRACK_HORZ_AREA:
145 case PART_TRACK_VERT_AREA:
146 case PART_THUMB_HORZ:
147 case PART_THUMB_VERT:
148 case PART_TRACK_HORZ_LEFT:
149 case PART_TRACK_HORZ_RIGHT:
150 case PART_TRACK_VERT_UPPER:
151 case PART_TRACK_VERT_LOWER:
152 break;
153 default:
154 bRetVal = false;
157 return bRetVal;
161 * IsNativeControlSupported()
162 * --------------------------
163 * Returns true if the platform supports native
164 * drawing of the control defined by nPart.
167 bool AquaSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
169 bool bOk = false;
171 // Native controls are now defaults
172 // If you want to disable experimental native controls code,
173 // just set the environment variable SAL_NO_NWF to something
174 // and vcl controls will be used as default again.
176 switch( nType )
178 case CTRL_PUSHBUTTON:
179 case CTRL_RADIOBUTTON:
180 case CTRL_CHECKBOX:
181 case CTRL_LISTNODE:
182 if( nPart == PART_ENTIRE_CONTROL )
183 return true;
184 break;
186 case CTRL_SCROLLBAR:
187 if( nPart == PART_DRAW_BACKGROUND_HORZ ||
188 nPart == PART_DRAW_BACKGROUND_VERT ||
189 nPart == PART_ENTIRE_CONTROL ||
190 nPart == HAS_THREE_BUTTONS )
191 return true;
192 break;
194 case CTRL_SLIDER:
195 if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
196 return true;
197 break;
199 case CTRL_EDITBOX:
200 if( nPart == PART_ENTIRE_CONTROL ||
201 nPart == HAS_BACKGROUND_TEXTURE )
202 return true;
203 break;
205 case CTRL_MULTILINE_EDITBOX:
206 if( nPart == PART_ENTIRE_CONTROL ||
207 nPart == HAS_BACKGROUND_TEXTURE )
208 return true;
209 break;
211 case CTRL_SPINBOX:
212 if( nPart == PART_ENTIRE_CONTROL ||
213 nPart == PART_ALL_BUTTONS ||
214 nPart == HAS_BACKGROUND_TEXTURE )
215 return true;
216 break;
218 case CTRL_SPINBUTTONS:
219 return false;
220 break;
222 case CTRL_COMBOBOX:
223 if( nPart == PART_ENTIRE_CONTROL ||
224 nPart == HAS_BACKGROUND_TEXTURE )
225 return true;
226 break;
228 case CTRL_LISTBOX:
229 if( nPart == PART_ENTIRE_CONTROL ||
230 nPart == PART_WINDOW ||
231 nPart == HAS_BACKGROUND_TEXTURE ||
232 nPart == PART_SUB_EDIT
234 return true;
235 break;
237 case CTRL_TAB_ITEM:
238 case CTRL_TAB_PANE:
239 case CTRL_TAB_BODY: // see vcl/source/window/tabpage.cxx
240 if( nPart == PART_ENTIRE_CONTROL ||
241 nPart == PART_TABS_DRAW_RTL ||
242 nPart == HAS_BACKGROUND_TEXTURE )
243 return true;
244 break;
246 // when PART_BUTTON is used, toolbar icons are not highlighted when mouse rolls over.
247 // More Aqua compliant
248 case CTRL_TOOLBAR:
249 if( nPart == PART_ENTIRE_CONTROL ||
250 nPart == PART_DRAW_BACKGROUND_HORZ ||
251 nPart == PART_DRAW_BACKGROUND_VERT)
252 return true;
253 break;
255 case CTRL_WINDOW_BACKGROUND:
256 if ( nPart == PART_BACKGROUND_WINDOW ||
257 nPart == PART_BACKGROUND_DIALOG )
258 return true;
259 break;
261 case CTRL_MENUBAR:
262 if( nPart == PART_ENTIRE_CONTROL )
263 return true;
264 break;
266 case CTRL_TOOLTIP: // ** TO DO
267 break;
269 case CTRL_MENU_POPUP:
270 if( nPart == PART_ENTIRE_CONTROL ||
271 nPart == PART_MENU_ITEM ||
272 nPart == PART_MENU_ITEM_CHECK_MARK ||
273 nPart == PART_MENU_ITEM_RADIO_MARK)
274 return true;
275 break;
276 case CTRL_PROGRESS:
277 case CTRL_INTROPROGRESS:
278 if( nPart == PART_ENTIRE_CONTROL )
279 return true;
280 break;
281 case CTRL_FRAME:
282 if( nPart == PART_BORDER )
283 return true;
284 break;
285 case CTRL_LISTNET:
286 if( nPart == PART_ENTIRE_CONTROL )
287 return true;
288 break;
291 return bOk;
295 * HitTestNativeControl()
297 * If the return value is true, bIsInside contains information whether
298 * aPos was or was not inside the native widget specified by the
299 * nType/nPart combination.
301 bool AquaSalGraphics::hitTestNativeControl( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion,
302 const Point& rPos, bool& rIsInside )
304 if ( nType == CTRL_SCROLLBAR )
306 Rectangle aRect;
307 bool bValid = AquaGetScrollRect( /* TODO: m_nScreen */ nPart, rControlRegion, aRect );
308 rIsInside = bValid && aRect.IsInside( rPos );
309 return bValid;
310 } // CTRL_SCROLLBAR
312 return false;
316 kThemeStateInactive = 0,
317 kThemeStateActive = 1,
318 kThemeStatePressed = 2,
319 kThemeStateRollover = 6,
320 kThemeStateUnavailable = 7,
321 kThemeStateUnavailableInactive = 8
322 kThemeStatePressedUp = 2,
323 kThemeStatePressedDown = 3
325 #define ControlState::ENABLED 0x0001
326 #define ControlState::FOCUSED 0x0002
327 #define ControlState::PRESSED 0x0004
328 #define ControlState::ROLLOVER 0x0008
329 #define ControlState::HIDDEN 0x0010
330 #define ControlState::DEFAULT 0x0020
331 #define ControlState::SELECTED 0x0040
332 #define CTRL_CACHING_ALLOWED 0x8000 // set when the control is completely visible (i.e. not clipped)
334 UInt32 AquaSalGraphics::getState( ControlState nState )
336 const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
337 if( !(nState & ControlState::ENABLED) || ! bDrawActive )
339 if( ! (nState & ControlState::HIDDEN) )
340 return kThemeStateInactive;
341 else
342 return kThemeStateUnavailableInactive;
345 if( nState & ControlState::HIDDEN )
346 return kThemeStateUnavailable;
348 if( nState & ControlState::PRESSED )
349 return kThemeStatePressed;
351 return kThemeStateActive;
354 UInt32 AquaSalGraphics::getTrackState( ControlState nState )
356 const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
357 if( ! (nState & ControlState::ENABLED) || ! bDrawActive )
358 return kThemeTrackInactive;
360 return kThemeTrackActive;
364 * DrawNativeControl()
366 * Draws the requested control described by nPart/nState.
368 * rControlRegion: The bounding region of the complete control in VCL frame coordinates.
369 * aValue: An optional value (tristate/numerical/string)
370 * aCaption: A caption or title string (like button text etc)
372 bool AquaSalGraphics::drawNativeControl(ControlType nType,
373 ControlPart nPart,
374 const Rectangle& rControlRegion,
375 ControlState nState,
376 const ImplControlValue& aValue,
377 const OUString& )
379 bool bOK = false;
381 if( ! CheckContext() )
382 return false;
384 CGContextSaveGState( mrContext );
386 Rectangle buttonRect = rControlRegion;
387 HIRect rc = ImplGetHIRectFromRectangle(buttonRect);
389 switch( nType )
392 case CTRL_COMBOBOX:
393 if ( nPart == HAS_BACKGROUND_TEXTURE ||
394 nPart == PART_ENTIRE_CONTROL )
396 HIThemeButtonDrawInfo aComboInfo;
397 aComboInfo.version = 0;
398 aComboInfo.kind = kThemeComboBox;
399 aComboInfo.state = getState( nState );
400 aComboInfo.value = kThemeButtonOn;
401 aComboInfo.adornment = kThemeAdornmentNone;
403 if( nState & ControlState::FOCUSED )
404 aComboInfo.adornment |= kThemeAdornmentFocus;
406 HIThemeDrawButton(&rc, &aComboInfo, mrContext, kHIThemeOrientationNormal,&rc);
407 bOK = true;
409 break;
411 case CTRL_TOOLBAR:
413 #if HAVE_FEATURE_MACOSX_SANDBOX
414 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
415 aMenuItemDrawInfo.version = 0;
416 aMenuItemDrawInfo.state = kThemeMenuActive;
417 aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
418 HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,NULL);
419 #else
420 if (rControlRegion.Top() == 0 && nPart == PART_DRAW_BACKGROUND_HORZ)
422 const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
423 CGFloat unifiedHeight = rControlRegion.GetHeight();
424 CGRect drawRect = CGRectMake(rControlRegion.Left(), rControlRegion.Top(), rControlRegion.GetWidth(), rControlRegion.GetHeight());
425 CUIDraw([NSWindow coreUIRenderer], drawRect, mrContext,
426 reinterpret_cast<CFDictionaryRef>([NSDictionary dictionaryWithObjectsAndKeys:
427 @"kCUIWidgetWindowFrame", @"widget",
428 @"regularwin", @"windowtype",
429 (bDrawActive ? @"normal" : @"inactive"), @"state",
430 [NSNumber numberWithDouble:unifiedHeight], @"kCUIWindowFrameUnifiedTitleBarHeightKey",
431 [NSNumber numberWithBool:NO], @"kCUIWindowFrameDrawTitleSeparatorKey",
432 [NSNumber numberWithBool:YES], @"is.flipped",
433 nil]),
434 nil);;
436 else
438 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
439 aMenuItemDrawInfo.version = 0;
440 aMenuItemDrawInfo.state = kThemeMenuActive;
441 aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
442 HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, mrContext, kHIThemeOrientationNormal, NULL);
444 #endif
445 bOK = true;
447 break;
449 case CTRL_WINDOW_BACKGROUND:
451 HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
452 aThemeBackgroundInfo.version = 0;
453 aThemeBackgroundInfo.state = getState( nState );
454 aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundActive;
455 // FIXME: without this magical offset there is a 2 pixel black border on the right and bottom
456 rc.size.width += 2;
457 rc.size.height += 2;
459 HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, mrContext, kHIThemeOrientationNormal);
460 CGContextFillRect( mrContext, rc );
461 bOK = true;
463 break;
465 case CTRL_MENUBAR:
466 case CTRL_MENU_POPUP:
468 if ((nPart == PART_ENTIRE_CONTROL) || (nPart == PART_MENU_ITEM )|| (nPart == HAS_BACKGROUND_TEXTURE ))
470 // FIXME: without this magical offset there is a 2 pixel black border on the right
471 rc.size.width += 2;
473 HIThemeMenuDrawInfo aMenuInfo;
474 aMenuInfo.version = 0;
475 aMenuInfo.menuType = kThemeMenuTypePullDown;
477 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
478 // the Aqua grey theme when the item is selected is drawn here.
479 aMenuItemDrawInfo.itemType = kThemeMenuItemPlain;
481 if ((nPart == PART_MENU_ITEM ) && (nState & ControlState::SELECTED))
483 // the blue theme when the item is selected is drawn here.
484 aMenuItemDrawInfo.state = kThemeMenuSelected;
486 else
488 // normal color for non selected item
489 aMenuItemDrawInfo.state = kThemeMenuActive;
492 // repaints the background of the pull down menu
493 HIThemeDrawMenuBackground(&rc,&aMenuInfo,mrContext,kHIThemeOrientationNormal);
495 // repaints the item either blue (selected) and/or Aqua grey (active only)
496 HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,&rc);
498 bOK = true;
500 else if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) {
501 if( nState & ControlState::PRESSED ) {//checked, else it is not displayed (see vcl/source/window/menu.cxx)
502 HIThemeTextInfo aTextInfo;
503 aTextInfo.version = 0;
504 aTextInfo.state = (nState & ControlState::ENABLED) ? kThemeStateInactive: kThemeStateActive;
505 aTextInfo.fontID = kThemeMenuItemMarkFont;
506 aTextInfo.horizontalFlushness=kHIThemeTextHorizontalFlushCenter;
507 aTextInfo.verticalFlushness=kHIThemeTextVerticalFlushTop;
508 aTextInfo.options=kHIThemeTextBoxOptionNone;
509 aTextInfo.truncationPosition=kHIThemeTextTruncationNone;
510 //aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone
512 if( nState & ControlState::SELECTED) aTextInfo.state = kThemeStatePressed; //item highlighted
514 UniChar mark=( nPart == PART_MENU_ITEM_CHECK_MARK ) ? kCheckUnicode: kBulletUnicode;//0x2713;
515 CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull);
516 HIThemeDrawTextBox(cfString, &rc, &aTextInfo, mrContext, kHIThemeOrientationNormal);
517 if (cfString)
518 CFRelease(cfString);
520 bOK = true;
524 break;
526 case CTRL_PUSHBUTTON:
528 // [ FIXME] : instead of use a value, vcl can retrieve correct values on the fly (to be implemented)
529 const int PB_Mini_Height = 15;
530 const int PB_Norm_Height = 21;
532 HIThemeButtonDrawInfo aPushInfo;
533 aPushInfo.version = 0;
535 // no animation
536 aPushInfo.animation.time.start = 0;
537 aPushInfo.animation.time.current = 0;
538 PushButtonValue const * pPBVal = aValue.getType() == CTRL_PUSHBUTTON ? static_cast<PushButtonValue const *>(&aValue) : NULL;
539 int nPaintHeight = static_cast<int>(rc.size.height);
541 if( pPBVal && pPBVal->mbBevelButton )
543 aPushInfo.kind = kThemeRoundedBevelButton;
545 else if( rc.size.height <= PB_Norm_Height )
547 aPushInfo.kind = kThemePushButtonMini;
548 nPaintHeight = PB_Mini_Height;
550 else if( pPBVal->mbSingleLine || rc.size.height < (PB_Norm_Height + PB_Norm_Height/2) )
552 aPushInfo.kind = kThemePushButtonNormal;
553 nPaintHeight = PB_Norm_Height;
555 // avoid clipping when focused
556 rc.origin.x += FOCUS_RING_WIDTH/2;
557 rc.size.width -= FOCUS_RING_WIDTH;
559 if( nState & ControlState::DEFAULT )
561 AquaBlinker::Blink( mpFrame, buttonRect );
562 // show correct animation phase
563 aPushInfo.animation.time.current = CFAbsoluteTimeGetCurrent();
566 else
567 aPushInfo.kind = kThemeBevelButton;
569 // translate the origin for controls with fixed paint height
570 // so content ends up somewhere sensible
571 int delta_y = static_cast<int>(rc.size.height) - nPaintHeight;
572 rc.origin.y += delta_y/2;
574 aPushInfo.state = getState( nState );
575 aPushInfo.value = ImplGetButtonValue( aValue.getTristateVal() );
577 aPushInfo.adornment = ( nState & ControlState::DEFAULT ) ?
578 kThemeAdornmentDefault :
579 kThemeAdornmentNone;
580 if( nState & ControlState::FOCUSED )
581 aPushInfo.adornment |= kThemeAdornmentFocus;
583 HIThemeDrawButton( &rc, &aPushInfo, mrContext, kHIThemeOrientationNormal, NULL );
584 bOK = true;
586 break;
588 case CTRL_RADIOBUTTON:
589 case CTRL_CHECKBOX:
591 HIThemeButtonDrawInfo aInfo;
592 aInfo.version = 0;
593 switch( nType )
595 case CTRL_RADIOBUTTON: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeRadioButton;
596 else aInfo.kind = kThemeSmallRadioButton;
597 break;
598 case CTRL_CHECKBOX: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeCheckBox;
599 else aInfo.kind = kThemeSmallCheckBox;
600 break;
603 aInfo.state = getState( nState );
605 ButtonValue aButtonValue = aValue.getTristateVal();
606 aInfo.value = ImplGetButtonValue( aButtonValue );
608 aInfo.adornment = ( nState & ControlState::DEFAULT ) ?
609 kThemeAdornmentDefault :
610 kThemeAdornmentNone;
611 if( nState & ControlState::FOCUSED )
612 aInfo.adornment |= kThemeAdornmentFocus;
613 HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL );
614 bOK = true;
616 break;
618 case CTRL_LISTNODE:
620 ButtonValue aButtonValue = aValue.getTristateVal();
622 if( AllSettings::GetLayoutRTL() && aButtonValue == BUTTONVALUE_OFF )
624 // FIXME: a value of kThemeDisclosureLeft
625 // should draw a theme compliant left disclosure triangle
626 // sadly this does not seem to work, so we'll draw a left
627 // grey equilateral triangle here ourselves.
628 // Perhaps some other HIThemeButtonDrawInfo setting would do the trick ?
630 CGContextSetShouldAntialias( mrContext, true );
631 CGFloat aGrey[] = { 0.45, 0.45, 0.45, 1.0 };
632 CGContextSetFillColor( mrContext, aGrey );
633 CGContextBeginPath( mrContext );
634 float x = rc.origin.x + rc.size.width;
635 float y = rc.origin.y;
636 CGContextMoveToPoint( mrContext, x, y );
637 y += rc.size.height;
638 CGContextAddLineToPoint( mrContext, x, y );
639 x -= rc.size.height * 0.866; // cos( 30 degree ) is approx. 0.866
640 y -= rc.size.height/2;
641 CGContextAddLineToPoint( mrContext, x, y );
642 CGContextDrawPath( mrContext, kCGPathEOFill );
644 else
646 HIThemeButtonDrawInfo aInfo;
647 aInfo.version = 0;
648 aInfo.kind = kThemeDisclosureTriangle;
649 aInfo.value = kThemeDisclosureRight;
650 aInfo.state = getState( nState );
652 aInfo.adornment = kThemeAdornmentNone;
654 switch( aButtonValue ) {
655 case BUTTONVALUE_ON: aInfo.value = kThemeDisclosureDown;//expanded
656 break;
657 case BUTTONVALUE_OFF:
658 // FIXME: this should have drawn a theme compliant disclosure triangle
659 // (see above)
660 if( AllSettings::GetLayoutRTL() )
662 aInfo.value = kThemeDisclosureLeft;//collapsed, RTL
664 break;
665 case BUTTONVALUE_DONTKNOW: //what to do?
666 default:
667 break;
670 HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL );
672 bOK = true;
674 break;
676 case CTRL_PROGRESS:
677 case CTRL_INTROPROGRESS:
679 long nProgressWidth = aValue.getNumericVal();
680 HIThemeTrackDrawInfo aTrackInfo;
681 aTrackInfo.version = 0;
682 aTrackInfo.kind = (rc.size.height > 10) ? kThemeProgressBarLarge : kThemeProgressBarMedium;
683 aTrackInfo.bounds = rc;
684 aTrackInfo.min = 0;
685 aTrackInfo.max = static_cast<SInt32>(rc.size.width);
686 aTrackInfo.value = nProgressWidth;
687 aTrackInfo.reserved = 0;
688 aTrackInfo.bounds.origin.y -= 2; // FIXME: magic for shadow
689 aTrackInfo.bounds.size.width -= 2; // FIXME: magic for shadow
690 aTrackInfo.attributes = kThemeTrackHorizontal;
691 if( AllSettings::GetLayoutRTL() )
692 aTrackInfo.attributes |= kThemeTrackRightToLeft;
693 aTrackInfo.enableState = getTrackState( nState );
694 // the intro bitmap never gets key anyway; we want to draw that enabled
695 if( nType == CTRL_INTROPROGRESS )
696 aTrackInfo.enableState = kThemeTrackActive;
697 aTrackInfo.filler1 = 0;
698 aTrackInfo.trackInfo.progress.phase = static_cast<UInt8>(CFAbsoluteTimeGetCurrent()*10.0);
700 HIThemeDrawTrack( &aTrackInfo, NULL, mrContext, kHIThemeOrientationNormal );
701 bOK = true;
703 break;
705 case CTRL_SLIDER:
707 SliderValue const * pSLVal = static_cast<SliderValue const *>(&aValue);
709 HIThemeTrackDrawInfo aTrackDraw;
710 aTrackDraw.kind = kThemeSliderMedium;
711 if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
713 aTrackDraw.bounds = rc;
714 aTrackDraw.min = pSLVal->mnMin;
715 aTrackDraw.max = pSLVal->mnMax;
716 aTrackDraw.value = pSLVal->mnCur;
717 aTrackDraw.reserved = 0;
718 aTrackDraw.attributes = kThemeTrackShowThumb;
719 if( nPart == PART_TRACK_HORZ_AREA )
720 aTrackDraw.attributes |= kThemeTrackHorizontal;
721 aTrackDraw.enableState = (nState & ControlState::ENABLED)
722 ? kThemeTrackActive : kThemeTrackInactive;
724 SliderTrackInfo aSlideInfo;
725 aSlideInfo.thumbDir = kThemeThumbUpward;
726 aSlideInfo.pressState = 0;
727 aTrackDraw.trackInfo.slider = aSlideInfo;
729 HIThemeDrawTrack( &aTrackDraw, NULL, mrContext, kHIThemeOrientationNormal );
730 bOK = true;
733 break;
735 case CTRL_SCROLLBAR:
737 const ScrollbarValue* pScrollbarVal = (aValue.getType() == CTRL_SCROLLBAR) ? static_cast<const ScrollbarValue*>(&aValue) : NULL;
739 if( nPart == PART_DRAW_BACKGROUND_VERT ||
740 nPart == PART_DRAW_BACKGROUND_HORZ )
742 HIThemeTrackDrawInfo aTrackDraw;
743 aTrackDraw.kind = kThemeMediumScrollBar;
744 // FIXME: the scrollbar length must be adjusted
745 if (nPart == PART_DRAW_BACKGROUND_VERT)
746 rc.size.height += 2;
747 else
748 rc.size.width += 2;
750 aTrackDraw.bounds = rc;
751 aTrackDraw.min = pScrollbarVal->mnMin;
752 aTrackDraw.max = pScrollbarVal->mnMax - pScrollbarVal->mnVisibleSize;
753 aTrackDraw.value = pScrollbarVal->mnCur;
754 aTrackDraw.reserved = 0;
755 aTrackDraw.attributes = kThemeTrackShowThumb;
756 if( nPart == PART_DRAW_BACKGROUND_HORZ )
757 aTrackDraw.attributes |= kThemeTrackHorizontal;
758 aTrackDraw.enableState = getTrackState( nState );
760 ScrollBarTrackInfo aScrollInfo;
761 aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize;
762 aScrollInfo.pressState = 0;
764 if ( pScrollbarVal->mnButton1State & ControlState::ENABLED )
766 if ( pScrollbarVal->mnButton1State & ControlState::PRESSED )
767 aScrollInfo.pressState = kThemeTopOutsideArrowPressed;
770 if ( pScrollbarVal->mnButton2State & ControlState::ENABLED )
772 if ( pScrollbarVal->mnButton2State & ControlState::PRESSED )
773 aScrollInfo.pressState = kThemeBottomOutsideArrowPressed;
776 if ( pScrollbarVal->mnThumbState & ControlState::ENABLED )
778 if ( pScrollbarVal->mnThumbState & ControlState::PRESSED )
779 aScrollInfo.pressState = kThemeThumbPressed;
782 aTrackDraw.trackInfo.scrollbar = aScrollInfo;
784 HIThemeDrawTrack( &aTrackDraw, NULL, mrContext, kHIThemeOrientationNormal );
785 bOK = true;
788 break;
790 case CTRL_TAB_PANE:
792 HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
793 aTabPaneDrawInfo.version = 1;
794 aTabPaneDrawInfo.state = kThemeStateActive;
795 aTabPaneDrawInfo.direction=kThemeTabNorth;
796 aTabPaneDrawInfo.size=kHIThemeTabSizeNormal;
797 aTabPaneDrawInfo.kind=kHIThemeTabKindNormal;
799 //the border is outside the rect rc for Carbon
800 //but for VCL it should be inside
801 rc.origin.x+=1;
802 rc.origin.y-=TAB_HEIGHT_NORMAL/2;
803 rc.size.height+=TAB_HEIGHT_NORMAL/2;
804 rc.size.width-=2;
806 HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal);
808 bOK = true;
810 break;
812 case CTRL_TAB_ITEM:
814 HIThemeTabDrawInfo aTabItemDrawInfo;
815 aTabItemDrawInfo.version=1;
816 aTabItemDrawInfo.style=kThemeTabNonFront;
817 aTabItemDrawInfo.direction=kThemeTabNorth;
818 aTabItemDrawInfo.size=kHIThemeTabSizeNormal;
819 aTabItemDrawInfo.adornment=kHIThemeTabAdornmentTrailingSeparator;
820 //State
821 if(nState & ControlState::SELECTED) {
822 aTabItemDrawInfo.style=kThemeTabFront;
824 if(nState & ControlState::FOCUSED) {
825 aTabItemDrawInfo.adornment|=kHIThemeTabAdornmentFocus;
828 //first, last or middle tab
829 aTabItemDrawInfo.position=kHIThemeTabPositionMiddle;
831 TabitemValue const * pTabValue = static_cast<TabitemValue const *>(&aValue);
832 unsigned int nAlignment = pTabValue->mnAlignment;
833 //TABITEM_LEFTALIGNED (and TABITEM_RIGHTALIGNED) for the leftmost (or rightmost) tab
834 //when there are several lines of tabs because there is only one first tab and one
835 //last tab and TABITEM_FIRST_IN_GROUP (and TABITEM_LAST_IN_GROUP) because when the
836 //line width is different from window width, there may not be TABITEM_RIGHTALIGNED
837 if( ( (nAlignment & TABITEM_LEFTALIGNED)&&(nAlignment & TABITEM_RIGHTALIGNED) ) ||
838 ( (nAlignment & TABITEM_FIRST_IN_GROUP)&&(nAlignment & TABITEM_LAST_IN_GROUP) )
839 ) //tab alone
840 aTabItemDrawInfo.position=kHIThemeTabPositionOnly;
841 else if((nAlignment & TABITEM_LEFTALIGNED)||(nAlignment & TABITEM_FIRST_IN_GROUP))
842 aTabItemDrawInfo.position=kHIThemeTabPositionFirst;
843 else if((nAlignment & TABITEM_RIGHTALIGNED)||(nAlignment & TABITEM_LAST_IN_GROUP))
844 aTabItemDrawInfo.position=kHIThemeTabPositionLast;
846 //support for RTL
847 //see issue 79748
848 if( AllSettings::GetLayoutRTL() ) {
849 if( aTabItemDrawInfo.position == kHIThemeTabPositionFirst )
850 aTabItemDrawInfo.position = kHIThemeTabPositionLast;
851 else if( aTabItemDrawInfo.position == kHIThemeTabPositionLast )
852 aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
855 rc.size.width+=2;//because VCL has 2 empty pixels between 2 tabs
856 rc.origin.x-=1;
858 HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc );
860 bOK=true;
862 break;
864 case CTRL_LISTBOX:
865 switch( nPart)
867 case PART_ENTIRE_CONTROL:
868 case PART_BUTTON_DOWN:
870 HIThemeButtonDrawInfo aListInfo;
871 aListInfo.version = 0;
872 aListInfo.kind = kThemePopupButton;
873 aListInfo.state = getState( nState );//kThemeStateInactive -> greyed
874 aListInfo.value = kThemeButtonOn;
876 aListInfo.adornment = kThemeAdornmentDefault;
877 if( nState & ControlState::FOCUSED )
878 aListInfo.adornment |= kThemeAdornmentFocus;
880 HIThemeDrawButton(&rc, &aListInfo, mrContext, kHIThemeOrientationNormal,&rc);
881 bOK = true;
882 break;
884 case PART_WINDOW:
886 HIThemeFrameDrawInfo aTextDrawInfo;
887 aTextDrawInfo.version=0;
888 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
889 aTextDrawInfo.state=getState( nState );
890 aTextDrawInfo.isFocused=false;
892 rc.size.width+=1;//else there's a white space because an OS X theme has no 3D border
893 rc.size.height+=1;
894 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
896 if(nState & ControlState::FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
898 bOK=true;
899 break;
902 break;
904 case CTRL_EDITBOX:
905 case CTRL_MULTILINE_EDITBOX:
907 HIThemeFrameDrawInfo aTextDrawInfo;
908 aTextDrawInfo.version=0;
909 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
910 aTextDrawInfo.state=getState( nState );
911 aTextDrawInfo.isFocused=false;
913 rc.size.width += 1; // else there may be a white space because an OS X theme has no 3D border
914 // change rc so that the frame will encompass only the content region
915 // see counterpart in GetNativeControlRegion
916 rc.size.width += 2;
917 rc.size.height += 2;
919 //CGContextSetFillColorWithColor
920 CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
921 //fill a white background, because drawFrame only draws the border
923 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
925 if(nState & ControlState::FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
927 bOK=true;
929 break;
931 case CTRL_SPINBOX:
933 if(nPart == PART_ENTIRE_CONTROL)
935 //text field:
936 HIThemeFrameDrawInfo aTextDrawInfo;
937 aTextDrawInfo.version=0;
938 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
939 aTextDrawInfo.state=getState( nState );
940 aTextDrawInfo.isFocused=false;
942 //rc.size.width contains the full size of the spinbox ie textfield + button
943 //so we remove the button width and the space between the button and the textfield
944 rc.size.width -= SPIN_BUTTON_SPACE + SPIN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
945 rc.origin.x += FOCUS_RING_WIDTH;
946 rc.origin.y += FOCUS_RING_WIDTH;
948 //CGContextSetFillColorWithColor
949 CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
950 //fill a white background, because drawFrame only draws the border
952 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
954 if(nState & ControlState::FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
956 //buttons:
957 const SpinbuttonValue* pSpinButtonVal = (aValue.getType() == CTRL_SPINBUTTONS) ? static_cast<const SpinbuttonValue*>(&aValue) : NULL;
958 ControlState nUpperState = ControlState::ENABLED;//state of the upper button
959 ControlState nLowerState = ControlState::ENABLED;//and of the lower button
960 if(pSpinButtonVal) {//pSpinButtonVal is sometimes null
961 nUpperState = (ControlState) pSpinButtonVal->mnUpperState;
962 nLowerState = (ControlState) pSpinButtonVal->mnLowerState;
964 HIThemeButtonDrawInfo aSpinInfo;
965 aSpinInfo.kind = kThemeIncDecButton;
966 aSpinInfo.state = kThemeStateActive;
967 if(nUpperState & ControlState::PRESSED)
968 aSpinInfo.state = kThemeStatePressedUp;
969 else if(nLowerState & ControlState::PRESSED)
970 aSpinInfo.state = kThemeStatePressedDown;
971 else if((nUpperState & ~ControlState::ENABLED)||(nLowerState & ~ControlState::ENABLED))
972 aSpinInfo.state = kThemeStateInactive;
973 else if((nUpperState & ControlState::ROLLOVER)||(nLowerState & ControlState::ROLLOVER))
974 aSpinInfo.state = kThemeStateRollover;
976 Rectangle aSpinRect( pSpinButtonVal->maUpperRect );
977 aSpinRect.Union( pSpinButtonVal->maLowerRect );
978 HIRect buttonRc = ImplGetHIRectFromRectangle(aSpinRect);
980 // FIXME: without this fuzz factor there is some unwanted clipping
981 if( AllSettings::GetLayoutRTL() )
982 buttonRc.origin.x -= FOCUS_RING_WIDTH - CLIP_FUZZ;
983 else
984 buttonRc.origin.x += FOCUS_RING_WIDTH + CLIP_FUZZ;
986 switch( aValue.getTristateVal() )
988 case BUTTONVALUE_ON: aSpinInfo.value = kThemeButtonOn;
989 break;
990 case BUTTONVALUE_OFF: aSpinInfo.value = kThemeButtonOff;
991 break;
992 case BUTTONVALUE_MIXED:
993 case BUTTONVALUE_DONTKNOW:
994 default: aSpinInfo.value = kThemeButtonMixed;
995 break;
998 aSpinInfo.adornment = ( (nUpperState & ControlState::DEFAULT) ||
999 (nLowerState & ControlState::DEFAULT) ) ?
1000 kThemeAdornmentDefault :
1001 kThemeAdornmentNone;
1002 if( (nUpperState & ControlState::FOCUSED) || (nLowerState & ControlState::FOCUSED))
1003 aSpinInfo.adornment |= kThemeAdornmentFocus;
1005 HIThemeDrawButton( &buttonRc, &aSpinInfo, mrContext, kHIThemeOrientationNormal, NULL );
1008 bOK=true;
1012 break;
1014 case CTRL_FRAME:
1016 DrawFrameFlags nStyle = static_cast<DrawFrameFlags>(aValue.getNumericVal());
1017 if( nPart == PART_BORDER ) {
1018 if(!( nStyle & DrawFrameFlags::Menu ) && !(nStyle & DrawFrameFlags::WindowBorder) )
1020 // #i84756# strange effects start to happen when HIThemeDrawFrame
1021 // meets the border of the window. These can be avoided by clipping
1022 // to the boundary of the frame
1023 if( rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight-3 )
1025 CGMutablePathRef rPath = CGPathCreateMutable();
1026 CGPathAddRect( rPath, NULL, CGRectMake( 0, 0, mpFrame->maGeometry.nWidth-1, mpFrame->maGeometry.nHeight-1 ) );
1028 CGContextBeginPath( mrContext );
1029 CGContextAddPath( mrContext, rPath );
1030 CGContextClip( mrContext );
1031 CGPathRelease( rPath );
1034 HIThemeFrameDrawInfo aTextDrawInfo;
1035 aTextDrawInfo.version=0;
1036 aTextDrawInfo.kind=kHIThemeFrameListBox;
1037 aTextDrawInfo.state=kThemeStateActive;
1038 aTextDrawInfo.isFocused=false;
1040 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
1042 bOK=true;
1046 break;
1048 case CTRL_LISTNET:
1050 //do nothing as there isn't net for listviews on macos
1051 bOK=true;
1053 break;
1057 CGContextRestoreGState( mrContext );
1059 /* #i90291# in most cases invalidating the whole control region instead
1060 of just the unclipped part of it is sufficient (and probably faster).
1061 However for the window background we should not unnecessarily enlarge
1062 the really changed rectangle since the difference is usually quite high
1063 (the background is always drawn as a whole since we don't know anything
1064 about its possible contents)
1066 if( nType == CTRL_WINDOW_BACKGROUND )
1068 CGRect aRect = { { 0, 0 }, { 0, 0 } };
1069 if( mxClipPath )
1070 aRect = CGPathGetBoundingBox( mxClipPath );
1071 if( aRect.size.width != 0 && aRect.size.height != 0 )
1072 buttonRect.Intersection( Rectangle( Point( static_cast<long int>(aRect.origin.x),
1073 static_cast<long int>(aRect.origin.y) ),
1074 Size( static_cast<long int>(aRect.size.width),
1075 static_cast<long int>(aRect.size.height) ) ) );
1078 RefreshRect( buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight() );
1080 return bOK;
1084 * GetNativeControlRegion()
1086 * If the return value is true, rNativeBoundingRegion
1087 * contains the true bounding region covered by the control
1088 * including any adornment, while rNativeContentRegion contains the area
1089 * within the control that can be safely drawn into without drawing over
1090 * the borders of the control.
1092 * rControlRegion: The bounding region of the control in VCL frame coordinates.
1093 * aValue: An optional value (tristate/numerical/string)
1094 * aCaption: A caption or title string (like button text etc)
1096 bool AquaSalGraphics::getNativeControlRegion( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, ControlState /*nState*/,
1097 const ImplControlValue& aValue, const OUString&,
1098 Rectangle &rNativeBoundingRegion, Rectangle &rNativeContentRegion )
1101 bool toReturn = false;
1103 Rectangle aCtrlBoundRect( rControlRegion );
1104 short x = aCtrlBoundRect.Left();
1105 short y = aCtrlBoundRect.Top();
1106 short w, h;
1108 sal_uInt8 nBorderCleanup = 0;
1110 switch (nType)
1112 case CTRL_SLIDER:
1114 if( nPart == PART_THUMB_HORZ )
1116 w = 19; // taken from HIG
1117 h = aCtrlBoundRect.GetHeight();
1118 rNativeBoundingRegion = rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1119 toReturn = true;
1121 else if( nPart == PART_THUMB_VERT )
1123 w = aCtrlBoundRect.GetWidth();
1124 h = 18; // taken from HIG
1125 rNativeBoundingRegion = rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1126 toReturn = true;
1129 break;
1131 case CTRL_SCROLLBAR:
1133 Rectangle aRect;
1134 if( AquaGetScrollRect( /* m_nScreen */ nPart, aCtrlBoundRect, aRect ) )
1136 toReturn = true;
1137 rNativeBoundingRegion = aRect;
1138 rNativeContentRegion = aRect;
1141 break;
1143 case CTRL_PUSHBUTTON:
1144 case CTRL_RADIOBUTTON:
1145 case CTRL_CHECKBOX:
1147 if ( nType == CTRL_PUSHBUTTON )
1149 w = aCtrlBoundRect.GetWidth();
1150 h = aCtrlBoundRect.GetHeight();
1152 else
1154 // checkbox and radio borders need cleanup after unchecking them
1155 nBorderCleanup = 4;
1157 // TEXT_SEPARATOR to respect Aqua HIG
1158 w = BUTTON_WIDTH + TEXT_SEPARATOR;
1159 h = BUTTON_HEIGHT;
1163 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h + nBorderCleanup) );
1164 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1166 toReturn = true;
1168 break;
1169 case CTRL_PROGRESS:
1171 Rectangle aRect( aCtrlBoundRect );
1172 if( aRect.GetHeight() < 16 )
1173 aRect.Bottom() = aRect.Top() + 9; // values taken from HIG for medium progress
1174 else
1175 aRect.Bottom() = aRect.Top() + 15; // values taken from HIG for large progress
1176 rNativeBoundingRegion = aRect;
1177 rNativeContentRegion = aRect;
1178 toReturn = true;
1180 break;
1182 case CTRL_INTROPROGRESS:
1184 Rectangle aRect( aCtrlBoundRect );
1185 aRect.Bottom() = aRect.Top() + INTRO_PROGRESS_HEIGHT; // values taken from HIG for medium progress
1186 rNativeBoundingRegion = aRect;
1187 rNativeContentRegion = aRect;
1188 toReturn = true;
1190 break;
1192 case CTRL_TAB_ITEM:
1194 w = aCtrlBoundRect.GetWidth() + 2*TAB_TEXT_OFFSET - 2*VCL_TAB_TEXT_OFFSET;
1195 h = TAB_HEIGHT_NORMAL+2;
1197 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1198 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1200 toReturn = true;
1202 break;
1204 case CTRL_EDITBOX:
1206 w = aCtrlBoundRect.GetWidth();
1207 if( w < 3+2*FOCUS_RING_WIDTH )
1208 w = 3+2*FOCUS_RING_WIDTH;
1209 h = TEXT_EDIT_HEIGHT_NORMAL+2*FOCUS_RING_WIDTH;
1210 if( h < aCtrlBoundRect.GetHeight() )
1211 h = aCtrlBoundRect.GetHeight();
1213 rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*(FOCUS_RING_WIDTH+1), h-2*(FOCUS_RING_WIDTH+1) ) );
1214 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1216 toReturn = true;
1218 break;
1219 case CTRL_LISTBOX:
1220 case CTRL_COMBOBOX:
1222 if( nPart == PART_ENTIRE_CONTROL )
1224 w = aCtrlBoundRect.GetWidth();
1225 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
1227 rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*FOCUS_RING_WIDTH, h ) );
1228 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1230 toReturn = true;
1232 else if( nPart == PART_BUTTON_DOWN )
1234 w = aCtrlBoundRect.GetWidth();
1235 if( w < 3+2*FOCUS_RING_WIDTH )
1236 w = 3+2*FOCUS_RING_WIDTH;
1237 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
1239 x += w-DROPDOWN_BUTTON_WIDTH - FOCUS_RING_WIDTH;
1240 y += FOCUS_RING_WIDTH;
1241 w = DROPDOWN_BUTTON_WIDTH;
1243 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1244 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
1246 toReturn = true;
1248 else if( nPart == PART_SUB_EDIT )
1250 w = aCtrlBoundRect.GetWidth();
1251 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
1253 x += FOCUS_RING_WIDTH;
1254 x += 3; // add an offset for rounded borders
1255 y += 2; // don't draw into upper border
1256 y += FOCUS_RING_WIDTH;
1257 w -= 3 + DROPDOWN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
1258 if( nType == CTRL_LISTBOX )
1259 w -= 9; // HIG specifies 9 units distance between dropdown button area and content
1260 h -= 4; // don't draw into lower border
1262 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1263 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
1265 toReturn = true;
1268 break;
1269 case CTRL_SPINBOX:
1270 if( nPart == PART_ENTIRE_CONTROL ) {
1271 w = aCtrlBoundRect.GetWidth();
1272 if( w < 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH )
1273 w = 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH;
1274 h = TEXT_EDIT_HEIGHT_NORMAL;
1276 rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y ), Size( w-2*FOCUS_RING_WIDTH, h ) );
1277 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1279 toReturn = true;
1281 else if( nPart == PART_SUB_EDIT ) {
1282 w = aCtrlBoundRect.GetWidth() - SPIN_BUTTON_SPACE - SPIN_BUTTON_WIDTH;
1283 h = TEXT_EDIT_HEIGHT_NORMAL;
1284 x += 4; // add an offset for rounded borders
1285 y += 2; // don't draw into upper border
1286 w -= 8; // offset for left and right rounded border
1287 h -= 4; // don't draw into upper or ower border
1289 rNativeContentRegion = Rectangle( Point( x + FOCUS_RING_WIDTH, y + FOCUS_RING_WIDTH ), Size( w - 2* FOCUS_RING_WIDTH, h ) );
1290 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1292 toReturn = true;
1294 else if( nPart == PART_BUTTON_UP ) {
1295 //aCtrlBoundRect.GetWidth() contains the width of the full control
1296 //ie the width of the textfield + button
1297 //x is the position of the left corner of the full control
1298 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
1299 y += FOCUS_RING_WIDTH - CLIP_FUZZ;
1300 w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
1301 h = SPIN_UPPER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
1303 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1304 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1306 toReturn = true;
1308 else if( nPart == PART_BUTTON_DOWN ) {
1309 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
1310 y += SPIN_UPPER_BUTTON_HEIGHT + FOCUS_RING_WIDTH - CLIP_FUZZ;
1311 w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
1312 h = SPIN_LOWER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
1314 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1315 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1317 toReturn = true;
1319 break;
1320 case CTRL_FRAME:
1322 DrawFrameStyle nStyle = static_cast<DrawFrameStyle>(aValue.getNumericVal() & 0x000f);
1323 DrawFrameFlags nFlags = static_cast<DrawFrameFlags>(aValue.getNumericVal() & 0xfff0);
1324 if( ( nPart == PART_BORDER ) &&
1325 !( nFlags & (DrawFrameFlags::Menu | DrawFrameFlags::WindowBorder | DrawFrameFlags::BorderWindowBorder) ) )
1327 Rectangle aRect(aCtrlBoundRect);
1328 if( nStyle == DrawFrameStyle::DoubleIn )
1330 aRect.Left() += 1;
1331 aRect.Top() += 1;
1332 //rRect.Right() -= 1;
1333 //rRect.Bottom() -= 1;
1335 else
1337 aRect.Left() += 1;
1338 aRect.Top() += 1;
1339 aRect.Right() -= 1;
1340 aRect.Bottom() -= 1;
1343 rNativeContentRegion = aRect;
1344 rNativeBoundingRegion = aRect;
1346 toReturn = true;
1349 break;
1351 case CTRL_MENUBAR:
1352 case CTRL_MENU_POPUP:
1354 if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) {
1356 w=10;
1357 h=10;//dimensions of the mark (10px font)
1359 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1360 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1362 toReturn = true;
1365 break;
1369 return toReturn;
1372 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */