1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "vcl/salnativewidgets.hxx"
25 #include "vcl/decoview.hxx"
26 #include "vcl/svapp.hxx"
27 #include "vcl/timer.hxx"
28 
29 #include "aqua/salconst.h"
30 #include "aqua/salgdi.h"
31 #include "aqua/salnativewidgets.h"
32 #include "aqua/saldata.hxx"
33 #include "aqua/salframe.h"
34 
35 #include "premac.h"
36 #include <Carbon/Carbon.h>
37 #include "postmac.h"
38 
39 class AquaBlinker : public Timer
40 {
41     AquaSalFrame*       mpFrame;
42     Rectangle           maInvalidateRect;
43 
44     AquaBlinker( AquaSalFrame* pFrame, const Rectangle& rRect )
45     : mpFrame( pFrame ), maInvalidateRect( rRect )
46     {
47         mpFrame->maBlinkers.push_back( this );
48     }
49 
50     public:
51 
52     static void Blink( AquaSalFrame*, const Rectangle&, int nTimeout = 80 );
53 
54     virtual void Timeout()
55     {
56         Stop();
57         if( AquaSalFrame::isAlive( mpFrame ) && mpFrame->mbShown )
58         {
59             mpFrame->maBlinkers.remove( this );
60             mpFrame->SendPaintEvent( &maInvalidateRect );
61         }
62         delete this;
63     }
64 };
65 
66 void AquaBlinker::Blink( AquaSalFrame* pFrame, const Rectangle& rRect, int nTimeout )
67 {
68     // prevent repeated paints from triggering themselves all the time
69     for( std::list< AquaBlinker* >::const_iterator it = pFrame->maBlinkers.begin();
70          it != pFrame->maBlinkers.end(); ++it )
71     {
72         if( (*it)->maInvalidateRect == rRect )
73             return;
74     }
75     AquaBlinker* pNew = new AquaBlinker( pFrame, rRect );
76     pNew->SetTimeout( nTimeout );
77     pNew->Start();
78 }
79 
80 ControlPart ImplgetCounterPart( ControlPart nPart )
81 {
82     ControlPart nCounterPart = 0;
83     switch (nPart)
84     {
85         case PART_BUTTON_UP:
86             nCounterPart = PART_BUTTON_DOWN;
87             break;
88         case PART_BUTTON_DOWN:
89             nCounterPart = PART_BUTTON_UP;
90             break;
91         case PART_BUTTON_LEFT:
92             nCounterPart = PART_BUTTON_RIGHT;
93             break;
94         case PART_BUTTON_RIGHT:
95             nCounterPart = PART_BUTTON_LEFT;
96             break;
97     }
98     return nCounterPart;
99 }
100 
101 
102 // Helper returns an HIRect
103 
104 static HIRect ImplGetHIRectFromRectangle(Rectangle aRect)
105 {
106     HIRect aHIRect;
107     aHIRect.origin.x = static_cast<float>(aRect.Left());
108     aHIRect.origin.y = static_cast<float>(aRect.Top());
109     aHIRect.size.width = static_cast<float>(aRect.GetWidth());
110     aHIRect.size.height = static_cast<float>(aRect.GetHeight());
111 	return aHIRect;
112 }
113 
114 static ThemeButtonValue ImplGetButtonValue( ButtonValue aButtonValue )
115 {
116     switch( aButtonValue )
117     {
118         case BUTTONVALUE_ON:
119             return kThemeButtonOn;
120             break;
121 
122         case BUTTONVALUE_OFF:
123             return kThemeButtonOff;
124             break;
125 
126         case BUTTONVALUE_MIXED:
127         case BUTTONVALUE_DONTKNOW:
128         default:
129             return kThemeButtonMixed;
130             break;
131     }
132 }
133 
134 static bool AquaGetScrollRect( /* TODO: int nScreen, */  ControlPart nPart,
135 	const Rectangle& rControlRect, Rectangle& rResultRect )
136 {
137 	bool bRetVal = true;
138     rResultRect = rControlRect;
139 
140     switch( nPart )
141     {
142         case PART_BUTTON_UP:
143 			if( GetSalData()->mbIsScrollbarDoubleMax )
144 				rResultRect.Top() = rControlRect.Bottom() - 2*BUTTON_HEIGHT;
145             rResultRect.Bottom() = rResultRect.Top() + BUTTON_HEIGHT;
146             break;
147 
148         case PART_BUTTON_DOWN:
149             rResultRect.Top() = rControlRect.Bottom() - BUTTON_HEIGHT;
150             break;
151 
152         case PART_BUTTON_LEFT:
153 			if( GetSalData()->mbIsScrollbarDoubleMax )
154 				rResultRect.Left() = rControlRect.Right() - 2*BUTTON_WIDTH;
155 			rResultRect.Right() = rResultRect.Left() + BUTTON_WIDTH;
156 			break;
157 
158         case PART_BUTTON_RIGHT:
159 			rResultRect.Left() = rControlRect.Right() - BUTTON_WIDTH;
160             break;
161 
162         case PART_TRACK_HORZ_AREA:
163             rResultRect.Right() -= BUTTON_WIDTH + 1;
164 			if( GetSalData()->mbIsScrollbarDoubleMax )
165 				rResultRect.Right() -= BUTTON_WIDTH;
166 			else
167 				rResultRect.Left() += BUTTON_WIDTH + 1;
168             break;
169 
170         case PART_TRACK_VERT_AREA:
171             rResultRect.Bottom() -= BUTTON_HEIGHT + 1;
172 			if( GetSalData()->mbIsScrollbarDoubleMax )
173 				rResultRect.Bottom() -= BUTTON_HEIGHT;
174 			else
175 				rResultRect.Top() += BUTTON_HEIGHT + 1;
176             break;
177         case PART_THUMB_HORZ:
178             if( GetSalData()->mbIsScrollbarDoubleMax )
179             {
180                 rResultRect.Left() += 8;
181                 rResultRect.Right() += 6;
182             }
183             else
184             {
185                 rResultRect.Left() += 4;
186                 rResultRect.Right() += 4;
187             }
188             break;
189         case PART_THUMB_VERT:
190             if( GetSalData()->mbIsScrollbarDoubleMax )
191             {
192                 rResultRect.Top() += 8;
193                 rResultRect.Bottom() += 8;
194             }
195             else
196             {
197                 rResultRect.Top() += 4;
198                 rResultRect.Bottom() += 4;
199             }
200             break;
201         case PART_TRACK_HORZ_LEFT:
202             if( GetSalData()->mbIsScrollbarDoubleMax )
203                 rResultRect.Right() += 8;
204             else
205                 rResultRect.Right() += 4;
206             break;
207         case PART_TRACK_HORZ_RIGHT:
208             if( GetSalData()->mbIsScrollbarDoubleMax )
209                 rResultRect.Left() += 6;
210             else
211                 rResultRect.Left() += 4;
212             break;
213         case PART_TRACK_VERT_UPPER:
214             if( GetSalData()->mbIsScrollbarDoubleMax )
215                 rResultRect.Bottom() += 8;
216             else
217                 rResultRect.Bottom() += 4;
218             break;
219         case PART_TRACK_VERT_LOWER:
220             if( GetSalData()->mbIsScrollbarDoubleMax )
221                 rResultRect.Top() += 8;
222             else
223                 rResultRect.Top() += 4;
224             break;
225 		default:
226 			bRetVal = false;
227     }
228 
229 	return bRetVal;
230 }
231 
232 /*
233  * IsNativeControlSupported()
234  * --------------------------
235  * Returns sal_True if the platform supports native
236  * drawing of the control defined by nPart.
237  *
238  */
239 sal_Bool AquaSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
240 {
241     bool bOk = sal_False;
242 
243     // Native controls are now defaults
244     // If you want to disable experimental native controls code,
245     // just set the environment variable SAL_NO_NWF to something
246     // and vcl controls will be used as default again.
247 
248     switch( nType )
249     {
250         case CTRL_PUSHBUTTON:
251         case CTRL_RADIOBUTTON:
252         case CTRL_CHECKBOX:
253         case CTRL_LISTNODE:
254             if( nPart == PART_ENTIRE_CONTROL )
255                 return true;
256             break;
257 
258         case CTRL_SCROLLBAR:
259             if( nPart == PART_DRAW_BACKGROUND_HORZ ||
260                 nPart == PART_DRAW_BACKGROUND_VERT ||
261                 nPart == PART_ENTIRE_CONTROL       ||
262                 nPart == HAS_THREE_BUTTONS )
263                 return true;
264             break;
265 
266         case CTRL_SLIDER:
267             if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
268                 return true;
269             break;
270 
271         case CTRL_EDITBOX:
272             if( nPart == PART_ENTIRE_CONTROL ||
273                 nPart == HAS_BACKGROUND_TEXTURE )
274                 return true;
275             break;
276 
277         case CTRL_MULTILINE_EDITBOX:
278             if( nPart == PART_ENTIRE_CONTROL ||
279                 nPart == HAS_BACKGROUND_TEXTURE )
280                 return true;
281             break;
282 
283         case CTRL_SPINBOX:
284             if( nPart == PART_ENTIRE_CONTROL ||
285                 nPart == PART_ALL_BUTTONS    ||
286                 nPart == HAS_BACKGROUND_TEXTURE )
287                 return true;
288             break;
289 
290         case CTRL_SPINBUTTONS:
291                 return false;
292             break;
293 
294 		case CTRL_COMBOBOX:
295             if( nPart == PART_ENTIRE_CONTROL ||
296                 nPart == HAS_BACKGROUND_TEXTURE )
297                 return true;
298             break;
299 
300         case CTRL_LISTBOX:
301             if( nPart == PART_ENTIRE_CONTROL    ||
302                 nPart == PART_WINDOW            ||
303                 nPart == HAS_BACKGROUND_TEXTURE ||
304                 nPart == PART_SUB_EDIT
305                 )
306                 return true;
307             break;
308 
309         case CTRL_TAB_ITEM:
310         case CTRL_TAB_PANE:
311         case CTRL_TAB_BODY:  // see vcl/source/window/tabpage.cxx
312         case CTRL_FIXEDBORDER:
313             if( nPart == PART_ENTIRE_CONTROL ||
314                 nPart == PART_TABS_DRAW_RTL ||
315                 nPart == HAS_BACKGROUND_TEXTURE )
316                 return true;
317             break;
318 
319         // when PART_BUTTON is used, toolbar icons are not highlighted when mouse rolls over.
320         // More Aqua compliant
321         case CTRL_TOOLBAR:
322             if( nPart == PART_ENTIRE_CONTROL       ||
323                 nPart == PART_DRAW_BACKGROUND_HORZ ||
324                 nPart == PART_DRAW_BACKGROUND_VERT)
325                 return true;
326             break;
327 
328         case  CTRL_WINDOW_BACKGROUND:
329             if ( nPart == PART_BACKGROUND_WINDOW ||
330                  nPart == PART_BACKGROUND_DIALOG )
331                  return true;
332             break;
333 
334         case CTRL_MENUBAR:
335             if( nPart == PART_ENTIRE_CONTROL )
336                 return true;
337             break;
338 
339         case CTRL_TOOLTIP: // ** TO DO
340             #if 0
341             if( nPart == PART_ENTIRE_CONTROL ) // we don't currently support the tooltip
342                 return true;
343             #endif
344             break;
345 
346         case CTRL_MENU_POPUP:
347             if( nPart == PART_ENTIRE_CONTROL       ||
348                 nPart == PART_MENU_ITEM            ||
349                 nPart == PART_MENU_ITEM_CHECK_MARK ||
350                 nPart == PART_MENU_ITEM_RADIO_MARK)
351                 return true;
352             break;
353         case CTRL_PROGRESS:
354         case CTRL_INTROPROGRESS:
355             if( nPart == PART_ENTIRE_CONTROL )
356                 return true;
357             break;
358         case CTRL_FRAME:
359             if( nPart == PART_BORDER )
360                 return true;
361             break;
362         case CTRL_LISTNET:
363             if( nPart == PART_ENTIRE_CONTROL )
364                 return true;
365             break;
366     }
367 
368     return bOk;
369 }
370 
371 /*
372  * HitTestNativeControl()
373  *
374  *  If the return value is sal_True, bIsInside contains information whether
375  *  aPos was or was not inside the native widget specified by the
376  *  nType/nPart combination.
377  */
378 sal_Bool AquaSalGraphics::hitTestNativeControl( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion,
379 					    const Point& rPos, sal_Bool& rIsInside )
380 {
381     if ( nType == CTRL_SCROLLBAR )
382     {
383 		Rectangle aRect;
384 		bool bValid = AquaGetScrollRect( /* TODO: m_nScreen */ nPart, rControlRegion, aRect );
385 		rIsInside = bValid ? aRect.IsInside( rPos ) : sal_False;
386         if( GetSalData()->mbIsScrollbarDoubleMax )
387         {
388             // in double max mode the actual trough is a little smaller than the track
389             // there is some visual filler that is not sensitive
390             if( bValid && rIsInside )
391             {
392                 if( nPart == PART_TRACK_HORZ_AREA )
393                 {
394                     // the left 4 pixels are not hit sensitive
395                     if( rPos.X() - aRect.Left() < 4 )
396                         rIsInside = sal_False;
397                 }
398                 else if( nPart == PART_TRACK_VERT_AREA )
399                 {
400                     // the top 4 pixels are not hit sensitive
401                     if( rPos.Y() - aRect.Top() < 4 )
402                         rIsInside = sal_False;
403                 }
404             }
405         }
406 		return bValid;
407     }  //  CTRL_SCROLLBAR
408 
409     return sal_False;
410 }
411 
412 /*
413   kThemeStateInactive = 0,
414    kThemeStateActive = 1,
415    kThemeStatePressed = 2,
416    kThemeStateRollover = 6,
417    kThemeStateUnavailable = 7,
418    kThemeStateUnavailableInactive = 8
419    kThemeStatePressedUp = 2,
420    kThemeStatePressedDown = 3
421 
422 #define CTRL_STATE_ENABLED		0x0001
423 #define CTRL_STATE_FOCUSED		0x0002
424 #define CTRL_STATE_PRESSED		0x0004
425 #define CTRL_STATE_ROLLOVER		0x0008
426 #define CTRL_STATE_HIDDEN		0x0010
427 #define CTRL_STATE_DEFAULT		0x0020
428 #define CTRL_STATE_SELECTED		0x0040
429 #define CTRL_CACHING_ALLOWED	0x8000  // set when the control is completely visible (i.e. not clipped)
430 */
431 UInt32 AquaSalGraphics::getState( ControlState nState )
432 {
433     const bool bDrawActive = mpFrame ? ([mpFrame->getNSWindow() isKeyWindow] ? true : false) : true;
434     if( (nState & CTRL_STATE_ENABLED) == 0 || ! bDrawActive )
435     {
436         if( (nState & CTRL_STATE_HIDDEN) == 0 )
437             return kThemeStateInactive;
438         else
439             return kThemeStateUnavailableInactive;
440     }
441 
442     if( (nState & CTRL_STATE_HIDDEN) != 0 )
443         return kThemeStateUnavailable;
444 
445     if( (nState & CTRL_STATE_PRESSED) != 0 )
446         return kThemeStatePressed;
447 
448     return kThemeStateActive;
449 }
450 
451 UInt32 AquaSalGraphics::getTrackState( ControlState nState )
452 {
453     const bool bDrawActive = mpFrame ? ([mpFrame->getNSWindow() isKeyWindow] ? true : false) : true;
454     if( (nState & CTRL_STATE_ENABLED) == 0 || ! bDrawActive )
455             return kThemeTrackInactive;
456 
457     return kThemeTrackActive;
458 }
459 
460 /*
461  * DrawNativeControl()
462  *
463  *  Draws the requested control described by nPart/nState.
464  *
465  *  rControlRegion:	The bounding region of the complete control in VCL frame coordinates.
466  *  aValue:		An optional value (tristate/numerical/string)
467  *  aCaption:	A caption or title string (like button text etc)
468  */
469 sal_Bool AquaSalGraphics::drawNativeControl(ControlType nType,
470 					ControlPart nPart,
471 					const Rectangle& rControlRegion,
472 					ControlState nState,
473 					const ImplControlValue& aValue,
474 					const rtl::OUString& )
475 {
476     sal_Bool bOK = sal_False;
477 
478     if( ! CheckContext() )
479         return false;
480 
481     CGContextSaveGState( mrContext );
482 
483     Rectangle buttonRect = rControlRegion;
484 	HIRect rc = ImplGetHIRectFromRectangle(buttonRect);
485 
486     /** Scrollbar parts code equivalent **
487     PART_BUTTON_UP 101
488     PART_BUTTON_DOWN 102
489 	PART_THUMB_VERT 211
490 	PART_TRACK_VERT_UPPER 201
491 	PART_TRACK_VERT_LOWER 203
492 
493 	PART_DRAW_BACKGROUND_HORZ 1000
494 	PART_DRAW_BACKGROUND_VERT 1001
495     **/
496 
497     switch( nType )
498     {
499 
500     case  CTRL_COMBOBOX:
501         if ( nPart == HAS_BACKGROUND_TEXTURE ||
502              nPart == PART_ENTIRE_CONTROL )
503         {
504             HIThemeButtonDrawInfo aComboInfo;
505             aComboInfo.version = 0;
506             aComboInfo.kind = kThemeComboBox;
507             aComboInfo.state = getState( nState );
508             aComboInfo.value = kThemeButtonOn;
509             aComboInfo.adornment = kThemeAdornmentNone;
510 
511             if( (nState & CTRL_STATE_FOCUSED) != 0 )
512                 aComboInfo.adornment |= kThemeAdornmentFocus;
513 
514             HIThemeDrawButton(&rc, &aComboInfo, mrContext, kHIThemeOrientationNormal,&rc);
515             bOK = true;
516         }
517         break;
518 
519     case CTRL_FIXEDBORDER:
520     case CTRL_TOOLBAR:
521         {
522             HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
523             aMenuItemDrawInfo.version = 0;
524             aMenuItemDrawInfo.state = kThemeMenuActive;
525             aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
526             HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,NULL);
527             bOK = true;
528         }
529         break;
530 
531         case CTRL_WINDOW_BACKGROUND:
532         {
533             HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
534             aThemeBackgroundInfo.version = 0;
535             aThemeBackgroundInfo.state = getState( nState );
536             aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundInactive;
537             // FIXME: without this magical offset there is a 2 pixel black border on the right and bottom
538             rc.size.width += 2;
539             rc.size.height += 2;
540 
541             HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, mrContext, kHIThemeOrientationNormal);
542             CGContextFillRect( mrContext, rc );
543             bOK = true;
544         }
545         break;
546 
547     case CTRL_MENUBAR:
548     case CTRL_MENU_POPUP:
549         {
550             if ((nPart == PART_ENTIRE_CONTROL) || (nPart == PART_MENU_ITEM )|| (nPart == HAS_BACKGROUND_TEXTURE ))
551             {
552                 // FIXME: without this magical offset there is a 2 pixel black border on the right
553                 rc.size.width += 2;
554 
555                 HIThemeMenuDrawInfo aMenuInfo;
556                 aMenuInfo.version = 0;
557                 aMenuInfo.menuType = kThemeMenuTypePullDown;
558 
559                 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
560                 // the Aqua grey theme when the item is selected is drawn here.
561                 aMenuItemDrawInfo.itemType = kThemeMenuItemPlain;
562 
563                 if ((nPart == PART_MENU_ITEM ) && (nState & CTRL_STATE_SELECTED))
564                 {
565                     // the blue theme when the item is selected is drawn here.
566                     aMenuItemDrawInfo.state = kThemeMenuSelected;
567                 }
568                 else
569                 {
570                     // normal color for non selected item
571                     aMenuItemDrawInfo.state = kThemeMenuActive;
572                 }
573 
574                 // repaints the background of the pull down menu
575                 HIThemeDrawMenuBackground(&rc,&aMenuInfo,mrContext,kHIThemeOrientationNormal);
576 
577                 // repaints the item either blue (selected) and/or Aqua grey (active only)
578                 HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,&rc);
579 
580                 bOK = true;
581             }
582             else if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) {
583                 if( nState & CTRL_STATE_PRESSED ) {//checked, else it is not displayed (see vcl/source/window/menu.cxx)
584                     HIThemeTextInfo aTextInfo;
585                     aTextInfo.version = 0;
586                     aTextInfo.state = ((nState & CTRL_STATE_ENABLED)==0) ? kThemeStateInactive: kThemeStateActive;
587                     aTextInfo.fontID = kThemeMenuItemMarkFont;
588                     aTextInfo.horizontalFlushness=kHIThemeTextHorizontalFlushCenter;
589                     aTextInfo.verticalFlushness=kHIThemeTextVerticalFlushTop;
590                     aTextInfo.options=kHIThemeTextBoxOptionNone;
591                     aTextInfo.truncationPosition=kHIThemeTextTruncationNone;
592                     //aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone
593 
594                     if( nState & CTRL_STATE_SELECTED) aTextInfo.state = kThemeStatePressed; //item highlighted
595 
596                     UniChar mark=( nPart == PART_MENU_ITEM_CHECK_MARK ) ? kCheckUnicode: kBulletUnicode;//0x2713;
597                     CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull);
598                     HIThemeDrawTextBox(cfString, &rc, &aTextInfo, mrContext, kHIThemeOrientationNormal);
599 					if (cfString)
600 						CFRelease(cfString);
601 
602                     bOK = true;
603                 }
604             }
605         }
606         break;
607 
608     case CTRL_PUSHBUTTON:
609         {
610             // [ FIXME] : instead of use a value, vcl can retrieve corect values on the fly (to be implemented)
611             const int PB_Mini_Height = 15;
612             const int PB_Norm_Height = 21;
613 
614             HIThemeButtonDrawInfo aPushInfo;
615             aPushInfo.version = 0;
616 
617             // no animation
618             aPushInfo.animation.time.start = 0;
619             aPushInfo.animation.time.current = 0;
620             PushButtonValue* pPBVal = aValue.getType() == CTRL_PUSHBUTTON ? (PushButtonValue*)&aValue : NULL;
621             int nPaintHeight = static_cast<int>(rc.size.height);
622 
623             if( pPBVal && pPBVal->mbBevelButton )
624             {
625                 aPushInfo.kind = kThemeRoundedBevelButton;
626             }
627             else if( rc.size.height <= PB_Norm_Height )
628             {
629                 aPushInfo.kind = kThemePushButtonMini;
630                 nPaintHeight = PB_Mini_Height;
631             }
632             else if( pPBVal->mbSingleLine || rc.size.height < (PB_Norm_Height + PB_Norm_Height/2) )
633             {
634                 aPushInfo.kind = kThemePushButtonNormal;
635                 nPaintHeight = PB_Norm_Height;
636 
637                 // avoid clipping when focused
638                 rc.origin.x += FOCUS_RING_WIDTH/2;
639                 rc.size.width -= FOCUS_RING_WIDTH;
640 
641                 if( (nState & CTRL_STATE_DEFAULT) != 0 )
642                 {
643                     AquaBlinker::Blink( mpFrame, buttonRect );
644                     // show correct animation phase
645                     aPushInfo.animation.time.current = CFAbsoluteTimeGetCurrent();
646                 }
647             }
648             else
649                 aPushInfo.kind = kThemeBevelButton;
650 
651             // translate the origin for controls with fixed paint height
652             // so content ends up somewhere sensible
653             int delta_y = static_cast<int>(rc.size.height) - nPaintHeight;
654             rc.origin.y += delta_y/2;
655 
656             aPushInfo.state = getState( nState );
657             aPushInfo.value = ImplGetButtonValue( aValue.getTristateVal() );
658 
659             aPushInfo.adornment = (( nState & CTRL_STATE_DEFAULT ) != 0) ?
660             kThemeAdornmentDefault :
661             kThemeAdornmentNone;
662             if( (nState & CTRL_STATE_FOCUSED) != 0 )
663                 aPushInfo.adornment |= kThemeAdornmentFocus;
664 
665             HIThemeDrawButton( &rc, &aPushInfo, mrContext, kHIThemeOrientationNormal, NULL );
666             bOK = true;
667         }
668         break;
669 
670     case CTRL_RADIOBUTTON:
671     case CTRL_CHECKBOX:
672         {
673             HIThemeButtonDrawInfo aInfo;
674             aInfo.version = 0;
675             switch( nType )
676             {
677             case CTRL_RADIOBUTTON: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeRadioButton;
678                                     else aInfo.kind = kThemeSmallRadioButton;
679                 break;
680             case CTRL_CHECKBOX:   if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeCheckBox;
681                                     else aInfo.kind = kThemeSmallCheckBox;
682                 break;
683             }
684 
685             aInfo.state = getState( nState );
686 
687             ButtonValue aButtonValue = aValue.getTristateVal();
688             aInfo.value = ImplGetButtonValue( aButtonValue );
689 
690             aInfo.adornment = (( nState & CTRL_STATE_DEFAULT ) != 0) ?
691             kThemeAdornmentDefault :
692             kThemeAdornmentNone;
693             if( (nState & CTRL_STATE_FOCUSED) != 0 )
694                 aInfo.adornment |= kThemeAdornmentFocus;
695             HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL );
696             bOK = true;
697         }
698         break;
699 
700     case CTRL_LISTNODE:
701         {
702             ButtonValue aButtonValue = aValue.getTristateVal();
703 
704             if( Application::GetSettings().GetLayoutRTL() && aButtonValue == BUTTONVALUE_OFF )
705             {
706                 // FIXME: a value of kThemeDisclosureLeft
707                 // should draw a theme compliant left disclosure triangle
708                 // sadly this does not seem to work, so we'll draw a left
709                 // grey equilateral triangle here ourselves.
710                 // Perhaps some other HIThemeButtonDrawInfo setting would do the trick ?
711 
712                 CGContextSetShouldAntialias( mrContext, true );
713                 CGFloat aGrey[] = { 0.45, 0.45, 0.45, 1.0 };
714                 CGContextSetFillColor( mrContext, aGrey );
715                 CGContextBeginPath( mrContext );
716                 CGFloat x = rc.origin.x + rc.size.width;
717                 CGFloat y = rc.origin.y;
718                 CGContextMoveToPoint( mrContext, x, y );
719                 y += rc.size.height;
720                 CGContextAddLineToPoint( mrContext, x, y );
721                 x -= rc.size.height * 0.866; // cos( 30 degree ) is approx. 0.866
722                 y -= rc.size.height/2;
723                 CGContextAddLineToPoint( mrContext, x, y );
724                 CGContextDrawPath( mrContext, kCGPathEOFill );
725             }
726             else
727             {
728                 HIThemeButtonDrawInfo aInfo;
729                 aInfo.version = 0;
730                 aInfo.kind = kThemeDisclosureTriangle;
731                 aInfo.value = kThemeDisclosureRight;
732                 aInfo.state = getState( nState );
733 
734                 aInfo.adornment = kThemeAdornmentNone;
735 
736                 switch( aButtonValue ) {
737                     case BUTTONVALUE_ON: aInfo.value = kThemeDisclosureDown;//expanded
738                         break;
739                     case BUTTONVALUE_OFF:
740                         // FIXME: this should have drawn a theme compliant disclosure triangle
741                         // (see above)
742                         if( Application::GetSettings().GetLayoutRTL() )
743                         {
744                             aInfo.value = kThemeDisclosureLeft;//collapsed, RTL
745                         }
746                         break;
747                     case BUTTONVALUE_DONTKNOW: //what to do?
748                     default:
749                         break;
750                 }
751 
752                 HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL );
753             }
754             bOK = true;
755         }
756         break;
757 
758     case CTRL_PROGRESS:
759     case CTRL_INTROPROGRESS:
760         {
761             long nProgressWidth = aValue.getNumericVal();
762             HIThemeTrackDrawInfo aTrackInfo;
763             aTrackInfo.version              = 0;
764             aTrackInfo.kind                 = (rc.size.height > 10) ? kThemeProgressBarLarge : kThemeProgressBarMedium;
765             aTrackInfo.bounds               = rc;
766             aTrackInfo.min                  = 0;
767             aTrackInfo.max                  = static_cast<SInt32>(rc.size.width);
768             aTrackInfo.value                = nProgressWidth;
769             aTrackInfo.reserved             = 0;
770             aTrackInfo.bounds.origin.y     -= 2; // FIXME: magic for shadow
771             aTrackInfo.bounds.size.width   -= 2; // FIXME: magic for shadow
772             aTrackInfo.attributes           = kThemeTrackHorizontal;
773             if( Application::GetSettings().GetLayoutRTL() )
774                 aTrackInfo.attributes      |= kThemeTrackRightToLeft;
775             aTrackInfo.enableState          = getTrackState( nState );
776             // the intro bitmap never gets key anyway; we want to draw that enabled
777             if( nType == CTRL_INTROPROGRESS )
778                 aTrackInfo.enableState          = kThemeTrackActive;
779             aTrackInfo.filler1              = 0;
780             aTrackInfo.trackInfo.progress.phase   = static_cast<UInt8>(CFAbsoluteTimeGetCurrent()*10.0);
781 
782             HIThemeDrawTrack( &aTrackInfo, NULL, mrContext, kHIThemeOrientationNormal );
783             bOK = true;
784         }
785         break;
786 
787     case CTRL_SLIDER:
788         {
789             SliderValue* pSLVal = (SliderValue*)&aValue;
790 
791             HIThemeTrackDrawInfo aTrackDraw;
792             aTrackDraw.kind = kThemeSliderMedium;
793             if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
794             {
795                 aTrackDraw.bounds = rc;
796                 aTrackDraw.min   = pSLVal->mnMin;
797                 aTrackDraw.max   = pSLVal->mnMax;;
798                 aTrackDraw.value = pSLVal->mnCur;
799                 aTrackDraw.reserved = 0;
800                 aTrackDraw.attributes = kThemeTrackShowThumb;
801                 if( nPart == PART_TRACK_HORZ_AREA )
802                     aTrackDraw.attributes |= kThemeTrackHorizontal;
803                 aTrackDraw.enableState = (nState & CTRL_STATE_ENABLED)
804                                          ? kThemeTrackActive : kThemeTrackInactive;
805 
806                 SliderTrackInfo aSlideInfo;
807                 aSlideInfo.thumbDir = kThemeThumbUpward;
808                 aSlideInfo.pressState = 0;
809                 aTrackDraw.trackInfo.slider = aSlideInfo;
810 
811                 HIThemeDrawTrack( &aTrackDraw, NULL, mrContext, kHIThemeOrientationNormal );
812                 bOK = true;
813             }
814         }
815         break;
816 
817     case CTRL_SCROLLBAR:
818         {
819             const ScrollbarValue* pScrollbarVal = (aValue.getType() == CTRL_SCROLLBAR) ? static_cast<const ScrollbarValue*>(&aValue) : NULL;
820 
821             if( nPart == PART_DRAW_BACKGROUND_VERT ||
822                 nPart == PART_DRAW_BACKGROUND_HORZ )
823             {
824                 HIThemeTrackDrawInfo aTrackDraw;
825                 aTrackDraw.kind = kThemeMediumScrollBar;
826                 // FIXME: the scrollbar length must be adjusted
827                 if (nPart == PART_DRAW_BACKGROUND_VERT)
828                     rc.size.height += 2;
829                 else
830                     rc.size.width += 2;
831 
832                 aTrackDraw.bounds = rc;
833                 aTrackDraw.min = pScrollbarVal->mnMin;
834                 aTrackDraw.max = pScrollbarVal->mnMax - pScrollbarVal->mnVisibleSize;
835                 aTrackDraw.value = pScrollbarVal->mnCur;
836                 aTrackDraw.reserved = 0;
837                 aTrackDraw.attributes = kThemeTrackShowThumb;
838                 if( nPart == PART_DRAW_BACKGROUND_HORZ )
839                     aTrackDraw.attributes |= kThemeTrackHorizontal;
840                 aTrackDraw.enableState = getTrackState( nState );
841 
842                 ScrollBarTrackInfo aScrollInfo;
843                 aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize;
844                 aScrollInfo.pressState = 0;
845 
846                 if ( pScrollbarVal->mnButton1State & CTRL_STATE_ENABLED )
847                 {
848                     if ( pScrollbarVal->mnButton1State & CTRL_STATE_PRESSED )
849                         aScrollInfo.pressState = kThemeTopOutsideArrowPressed;
850                 }
851 
852                 if ( pScrollbarVal->mnButton2State & CTRL_STATE_ENABLED )
853                 {
854                     if ( pScrollbarVal->mnButton2State & CTRL_STATE_PRESSED )
855                         aScrollInfo.pressState = kThemeBottomOutsideArrowPressed;
856                 }
857 
858                 if ( pScrollbarVal->mnThumbState & CTRL_STATE_ENABLED )
859                 {
860                     if ( pScrollbarVal->mnThumbState & CTRL_STATE_PRESSED )
861                         aScrollInfo.pressState = kThemeThumbPressed;
862                 }
863 
864                 aTrackDraw.trackInfo.scrollbar = aScrollInfo;
865 
866                 HIThemeDrawTrack( &aTrackDraw, NULL, mrContext, kHIThemeOrientationNormal );
867                 bOK = true;
868             }
869         }
870         break;
871 
872 //#define OLD_TAB_STYLE
873 #ifdef OLD_TAB_STYLE
874     case CTRL_TAB_PANE:
875         {
876             HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
877             aTabPaneDrawInfo.version = 0;
878             aTabPaneDrawInfo.state = kThemeStateActive;
879             aTabPaneDrawInfo.direction=kThemeTabNorth;
880             aTabPaneDrawInfo.size=kHIThemeTabSizeNormal;
881 
882             //the border is outside the rect rc for Carbon
883             //but for VCL it should be inside
884             rc.origin.x+=1;
885             rc.size.width-=2;
886 
887             HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal);
888             bOK = true;
889         }
890         break;
891 
892     case CTRL_TAB_ITEM:
893         {
894             HIThemeTabDrawInfo aTabItemDrawInfo;
895             aTabItemDrawInfo.version=0;
896             aTabItemDrawInfo.style=kThemeTabNonFront;
897             aTabItemDrawInfo.direction=kThemeTabNorth;
898             aTabItemDrawInfo.size=kHIThemeTabSizeNormal;
899             aTabItemDrawInfo.adornment=kHIThemeTabAdornmentNone;
900 
901             if(nState & CTRL_STATE_SELECTED) {
902                 aTabItemDrawInfo.style=kThemeTabFront;
903             }
904             if(nState & CTRL_STATE_FOCUSED) {
905                 aTabItemDrawInfo.adornment=kHIThemeTabAdornmentFocus;
906             }
907 
908             /*if(rc.size.height>=TAB_HEIGHT_NORMAL) rc.size.height=TAB_HEIGHT_NORMAL;
909             else if(rc.size.height>=TAB_HEIGHT_SMALL) rc.size.height=TAB_HEIGHT_SMALL;
910             else rc.size.height=TAB_HEIGHT_MINI;*/
911             //now we only use the default size
912             rc.size.height=TAB_HEIGHT_NORMAL;
913 
914             HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc );
915 
916             bOK=true;
917         }
918         break;
919 #else
920     case CTRL_TAB_PANE:
921         {
922             HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
923             aTabPaneDrawInfo.version = 1;
924             aTabPaneDrawInfo.state = kThemeStateActive;
925             aTabPaneDrawInfo.direction=kThemeTabNorth;
926             aTabPaneDrawInfo.size=kHIThemeTabSizeNormal;
927             aTabPaneDrawInfo.kind=kHIThemeTabKindNormal;
928 
929             //the border is outside the rect rc for Carbon
930             //but for VCL it should be inside
931             rc.origin.x+=1;
932             rc.origin.y-=TAB_HEIGHT_NORMAL/2;
933             rc.size.height+=TAB_HEIGHT_NORMAL/2;
934             rc.size.width-=2;
935 
936             HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal);
937 
938             bOK = true;
939         }
940         break;
941 
942     case CTRL_TAB_ITEM:
943         {
944             HIThemeTabDrawInfo aTabItemDrawInfo;
945             aTabItemDrawInfo.version=1;
946             aTabItemDrawInfo.style=kThemeTabNonFront;
947             aTabItemDrawInfo.direction=kThemeTabNorth;
948             aTabItemDrawInfo.size=kHIThemeTabSizeNormal;
949             aTabItemDrawInfo.adornment=kHIThemeTabAdornmentTrailingSeparator;
950             //State
951             if(nState & CTRL_STATE_SELECTED) {
952                 aTabItemDrawInfo.style=kThemeTabFront;
953             }
954             if(nState & CTRL_STATE_FOCUSED) {
955                 aTabItemDrawInfo.adornment|=kHIThemeTabAdornmentFocus;
956             }
957 
958             //first, last or middle tab
959             aTabItemDrawInfo.position=kHIThemeTabPositionMiddle;
960 
961             TabitemValue* pTabValue = (TabitemValue *) &aValue;
962             unsigned int nAlignment = pTabValue->mnAlignment;
963             //TABITEM_LEFTALIGNED (and TABITEM_RIGHTALIGNED) for the leftmost (or rightmost) tab
964             //when there are several lines of tabs because there is only one first tab and one
965             //last tab and TABITEM_FIRST_IN_GROUP (and TABITEM_LAST_IN_GROUP) because when the
966             //line width is different from window width, there may not be TABITEM_RIGHTALIGNED
967             if( ( (nAlignment & TABITEM_LEFTALIGNED)&&(nAlignment & TABITEM_RIGHTALIGNED) ) ||
968                 ( (nAlignment & TABITEM_FIRST_IN_GROUP)&&(nAlignment & TABITEM_LAST_IN_GROUP) )
969                ) //tab alone
970                 aTabItemDrawInfo.position=kHIThemeTabPositionOnly;
971             else if((nAlignment & TABITEM_LEFTALIGNED)||(nAlignment & TABITEM_FIRST_IN_GROUP))
972                 aTabItemDrawInfo.position=kHIThemeTabPositionFirst;
973             else if((nAlignment & TABITEM_RIGHTALIGNED)||(nAlignment & TABITEM_LAST_IN_GROUP))
974                 aTabItemDrawInfo.position=kHIThemeTabPositionLast;
975 
976             //support for RTL
977             //see issue 79748
978             if( Application::GetSettings().GetLayoutRTL() ) {
979                 if( aTabItemDrawInfo.position == kHIThemeTabPositionFirst )
980                         aTabItemDrawInfo.position = kHIThemeTabPositionLast;
981                 else if( aTabItemDrawInfo.position == kHIThemeTabPositionLast )
982                         aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
983             }
984 
985             rc.size.width+=2;//because VCL has 2 empty pixels between 2 tabs
986             rc.origin.x-=1;
987 
988             HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc );
989 
990             bOK=true;
991         }
992         break;
993 #endif
994 
995     case  CTRL_LISTBOX:
996         switch( nPart)
997         {
998             case PART_ENTIRE_CONTROL:
999             case PART_BUTTON_DOWN:
1000             {
1001                 HIThemeButtonDrawInfo aListInfo;
1002                 aListInfo.version = 0;
1003                 aListInfo.kind = kThemePopupButton;
1004                 aListInfo.state = getState( nState );//kThemeStateInactive -> greyed
1005                 aListInfo.value = kThemeButtonOn;
1006 
1007                 aListInfo.adornment = kThemeAdornmentDefault;
1008                 if( (nState & CTRL_STATE_FOCUSED) != 0 )
1009                     aListInfo.adornment |= kThemeAdornmentFocus;
1010 
1011                 HIThemeDrawButton(&rc, &aListInfo, mrContext, kHIThemeOrientationNormal,&rc);
1012                 bOK = true;
1013                 break;
1014             }
1015             case PART_WINDOW:
1016             {
1017                 HIThemeFrameDrawInfo aTextDrawInfo;
1018                 aTextDrawInfo.version=0;
1019                 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
1020                 aTextDrawInfo.state=getState( nState );
1021                 aTextDrawInfo.isFocused=false;
1022 
1023                 rc.size.width+=1;//else there's a white space because aqua theme hasn't a 3D border
1024                 rc.size.height+=1;
1025                 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
1026 
1027                 if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
1028 
1029                 bOK=true;
1030                 break;
1031             }
1032         }
1033         break;
1034 
1035     case CTRL_EDITBOX:
1036     case CTRL_MULTILINE_EDITBOX:
1037         {
1038             HIThemeFrameDrawInfo aTextDrawInfo;
1039             aTextDrawInfo.version=0;
1040             aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
1041             aTextDrawInfo.state=getState( nState );
1042             aTextDrawInfo.isFocused=false;
1043 
1044             rc.size.width  += 1; // else there may be a white space because aqua theme hasn't a 3D border
1045             // change rc so that the frame will encompass only the content region
1046             // see counterpart in GetNativeControlRegion
1047             rc.size.width  += 2;
1048             rc.size.height += 2;
1049 
1050             //CGContextSetFillColorWithColor
1051             CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
1052             //fill a white background, because drawFrame only draws the border
1053 
1054             HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
1055 
1056             if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
1057 
1058             bOK=true;
1059         }
1060         break;
1061 
1062     case CTRL_SPINBOX:
1063         {
1064             if(nPart == PART_ENTIRE_CONTROL)
1065             {
1066                 //text field:
1067                 HIThemeFrameDrawInfo aTextDrawInfo;
1068                 aTextDrawInfo.version=0;
1069                 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
1070                 aTextDrawInfo.state=getState( nState );
1071                 aTextDrawInfo.isFocused=false;
1072 
1073                 //rc.size.width contains the full size of the spinbox ie textfield + button
1074                 //so we remove the button width and the space between the button and the textfield
1075                 rc.size.width -= SPIN_BUTTON_SPACE + SPIN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
1076                 rc.origin.x += FOCUS_RING_WIDTH;
1077                 rc.origin.y += FOCUS_RING_WIDTH;
1078 
1079                 //CGContextSetFillColorWithColor
1080                 CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
1081                 //fill a white background, because drawFrame only draws the border
1082 
1083                 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
1084 
1085                 if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
1086 
1087                 //buttons:
1088                 const SpinbuttonValue* pSpinButtonVal = (aValue.getType() == CTRL_SPINBUTTONS) ? static_cast<const SpinbuttonValue*>(&aValue) : NULL;
1089                 ControlState nUpperState = CTRL_STATE_ENABLED;//state of the upper button
1090                 ControlState nLowerState = CTRL_STATE_ENABLED;//and of the lower button
1091                 if(pSpinButtonVal) {//pSpinButtonVal is sometimes null
1092                     nUpperState = (ControlState) pSpinButtonVal->mnUpperState;
1093                     nLowerState = (ControlState) pSpinButtonVal->mnLowerState;
1094 
1095                     HIThemeButtonDrawInfo aSpinInfo;
1096                     aSpinInfo.kind = kThemeIncDecButton;
1097                     aSpinInfo.state = kThemeStateActive;
1098                     if(nUpperState & CTRL_STATE_PRESSED)
1099                         aSpinInfo.state = kThemeStatePressedUp;
1100                     else if(nLowerState & CTRL_STATE_PRESSED)
1101                         aSpinInfo.state = kThemeStatePressedDown;
1102                     else if((nUpperState & ~CTRL_STATE_ENABLED)||(nLowerState & ~CTRL_STATE_ENABLED))
1103                         aSpinInfo.state = kThemeStateInactive;
1104                     else if((nUpperState & CTRL_STATE_ROLLOVER)||(nLowerState & CTRL_STATE_ROLLOVER))
1105                         aSpinInfo.state = kThemeStateRollover;
1106 
1107                     Rectangle aSpinRect( pSpinButtonVal->maUpperRect );
1108                     aSpinRect.Union( pSpinButtonVal->maLowerRect );
1109                     HIRect buttonRc = ImplGetHIRectFromRectangle(aSpinRect);
1110 
1111                     // FIXME: without this fuzz factor there is some unwanted clipping
1112                     if( Application::GetSettings().GetLayoutRTL() )
1113                         buttonRc.origin.x -= FOCUS_RING_WIDTH - CLIP_FUZZ;
1114                     else
1115                         buttonRc.origin.x += FOCUS_RING_WIDTH + CLIP_FUZZ;
1116 
1117                     switch( aValue.getTristateVal() )
1118                     {
1119                         case BUTTONVALUE_ON:        aSpinInfo.value = kThemeButtonOn;
1120                                                     break;
1121                         case BUTTONVALUE_OFF:       aSpinInfo.value = kThemeButtonOff;
1122                                                     break;
1123                         case BUTTONVALUE_MIXED:
1124                         case BUTTONVALUE_DONTKNOW:
1125                         default:                    aSpinInfo.value = kThemeButtonMixed;
1126                                                     break;
1127                     }
1128 
1129                     aSpinInfo.adornment = ( ((nUpperState & CTRL_STATE_DEFAULT) != 0 ) ||
1130                                             ((nLowerState & CTRL_STATE_DEFAULT) != 0 )) ?
1131                                        kThemeAdornmentDefault :
1132                                        kThemeAdornmentNone;
1133                     if( ((nUpperState & CTRL_STATE_FOCUSED) != 0 ) || ((nLowerState & CTRL_STATE_FOCUSED) != 0 ))
1134                         aSpinInfo.adornment |= kThemeAdornmentFocus;
1135 
1136                     HIThemeDrawButton( &buttonRc, &aSpinInfo, mrContext, kHIThemeOrientationNormal, NULL );
1137                 }
1138 
1139                 bOK=true;
1140             }
1141 
1142         }
1143         break;
1144 
1145     case CTRL_FRAME:
1146         {
1147             sal_uInt16 nStyle = aValue.getNumericVal();
1148             if( nPart == PART_BORDER ) {
1149                 if(!( nStyle & FRAME_DRAW_MENU ) && !(nStyle & FRAME_DRAW_WINDOWBORDER) )
1150                 {
1151                     // #i84756# strange effects start to happen when HIThemeDrawFrame
1152                     // meets the border of the window. These can be avoided by clipping
1153                     // to the boundary of the frame
1154                     if( rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight-3 )
1155                     {
1156                         CGMutablePathRef rPath = CGPathCreateMutable();
1157                         CGPathAddRect( rPath, NULL, CGRectMake( 0, 0, mpFrame->maGeometry.nWidth-1, mpFrame->maGeometry.nHeight-1 ) );
1158 
1159                         CGContextBeginPath( mrContext );
1160                         CGContextAddPath( mrContext, rPath );
1161                         CGContextClip( mrContext );
1162                         CGPathRelease( rPath );
1163                     }
1164 
1165                     HIThemeFrameDrawInfo aTextDrawInfo;
1166                     aTextDrawInfo.version=0;
1167                     aTextDrawInfo.kind=kHIThemeFrameListBox;
1168                     aTextDrawInfo.state=kThemeStateActive;
1169                     aTextDrawInfo.isFocused=false;
1170 
1171                     HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
1172 
1173                     bOK=true;
1174                 }
1175             }
1176         }
1177         break;
1178 
1179     case CTRL_LISTNET:
1180         {
1181            //do nothing as there isn't net for listviews on macos
1182             bOK=true;
1183         }
1184         break;
1185 
1186     }
1187 
1188     CGContextRestoreGState( mrContext );
1189 
1190     /* #i90291# in most cases invalidating the whole control region instead
1191        of just the unclipped part of it is sufficient (and probably faster).
1192        However for the window background we should not unnecessarily enlarge
1193        the really changed rectangle since the difference is usually quite high
1194        (the background is always drawn as a whole since we don't know anything
1195        about its possible contents)
1196     */
1197     if( nType == CTRL_WINDOW_BACKGROUND )
1198     {
1199         CGRect aRect = { { 0, 0 }, { 0, 0 } };
1200         if( mxClipPath )
1201             aRect = CGPathGetBoundingBox( mxClipPath );
1202         if( aRect.size.width != 0 && aRect.size.height != 0 )
1203             buttonRect.Intersection( Rectangle( Point( static_cast<long int>(aRect.origin.x),
1204 							static_cast<long int>(aRect.origin.y) ),
1205                                                 Size( 	static_cast<long int>(aRect.size.width),
1206 							static_cast<long int>(aRect.size.height) ) ) );
1207     }
1208 
1209     RefreshRect( buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight() );
1210 
1211     return bOK;
1212 }
1213 
1214 /*
1215  * DrawNativeControlText()
1216  *
1217  *  OPTIONAL.  Draws the requested text for the control described by nPart/nState.
1218  *     Used if text not drawn by DrawNativeControl().
1219  *
1220  *  rControlRegion:	The bounding region of the complete control in VCL frame coordinates.
1221  *  aValue:		An optional value (tristate/numerical/string)
1222  *  aCaption:	A caption or title string (like button text etc)
1223  */
1224 sal_Bool AquaSalGraphics::drawNativeControlText( ControlType /*nType*/, ControlPart /*nPart*/, const Rectangle& /*rControlRegion*/,
1225                                                ControlState /*nState*/, const ImplControlValue& /*aValue*/,
1226                                                const rtl::OUString& )
1227 {
1228 	return( sal_False );
1229 }
1230 
1231 
1232 /*
1233  * GetNativeControlRegion()
1234  *
1235  *  If the return value is sal_True, rNativeBoundingRegion
1236  *  contains the true bounding region covered by the control
1237  *  including any adornment, while rNativeContentRegion contains the area
1238  *  within the control that can be safely drawn into without drawing over
1239  *  the borders of the control.
1240  *
1241  *  rControlRegion:	The bounding region of the control in VCL frame coordinates.
1242  *  aValue:		An optional value (tristate/numerical/string)
1243  *  aCaption:		A caption or title string (like button text etc)
1244  */
1245 sal_Bool AquaSalGraphics::getNativeControlRegion( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, ControlState /*nState*/,
1246                                                const ImplControlValue& aValue, const rtl::OUString&,
1247                                                 Rectangle &rNativeBoundingRegion, Rectangle &rNativeContentRegion )
1248 
1249 {
1250 	sal_Bool toReturn = sal_False;
1251 
1252 	Rectangle aCtrlBoundRect( rControlRegion );
1253     short x = aCtrlBoundRect.Left();
1254     short y = aCtrlBoundRect.Top();
1255     short w, h;
1256 
1257     sal_uInt8 nBorderCleanup = 0;
1258 
1259     switch (nType)
1260     {
1261         case CTRL_SLIDER:
1262             {
1263                 if( nPart == PART_THUMB_HORZ )
1264                 {
1265                     w = 19; // taken from HIG
1266                     h = aCtrlBoundRect.GetHeight();
1267                     rNativeBoundingRegion = rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1268                     toReturn = true;
1269                 }
1270                 else if( nPart == PART_THUMB_VERT )
1271                 {
1272                     w = aCtrlBoundRect.GetWidth();
1273                     h = 18; // taken from HIG
1274                     rNativeBoundingRegion = rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1275                     toReturn = true;
1276                 }
1277             }
1278             break;
1279 
1280         case CTRL_SCROLLBAR:
1281             {
1282 				Rectangle aRect;
1283 				if( AquaGetScrollRect( /* m_nScreen */ nPart, aCtrlBoundRect, aRect ) )
1284                 {
1285 					toReturn = sal_True;
1286 					rNativeBoundingRegion = aRect;
1287 					rNativeContentRegion = aRect;
1288                 }
1289             }
1290             break;
1291 
1292         case CTRL_PUSHBUTTON:
1293         case CTRL_RADIOBUTTON:
1294         case CTRL_CHECKBOX:
1295             {
1296                 if ( nType == CTRL_PUSHBUTTON )
1297                 {
1298                     w = aCtrlBoundRect.GetWidth();
1299                     h = aCtrlBoundRect.GetHeight();
1300                 }
1301                 else
1302                 {
1303                     // checkbox and radio borders need cleanup after unchecking them
1304                     nBorderCleanup = 4;
1305 
1306                     // TEXT_SEPARATOR to respect Aqua HIG
1307                     w = BUTTON_WIDTH + TEXT_SEPARATOR;
1308                     h = BUTTON_HEIGHT;
1309 
1310                 }
1311 
1312                 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h + nBorderCleanup) );
1313                 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1314 
1315                 toReturn = sal_True;
1316             }
1317             break;
1318         case CTRL_PROGRESS:
1319             {
1320                 Rectangle aRect( aCtrlBoundRect );
1321                 if( aRect.GetHeight() < 16 )
1322                     aRect.Bottom() = aRect.Top() + 9; // values taken from HIG for medium progress
1323                 else
1324                     aRect.Bottom() = aRect.Top() + 15; // values taken from HIG for large progress
1325                 rNativeBoundingRegion = aRect;
1326                 rNativeContentRegion = aRect;
1327                 toReturn = sal_True;
1328             }
1329             break;
1330 
1331         case CTRL_INTROPROGRESS:
1332             {
1333                 Rectangle aRect( aCtrlBoundRect );
1334                 aRect.Bottom() = aRect.Top() + INTRO_PROGRESS_HEIGHT; // values taken from HIG for medium progress
1335                 rNativeBoundingRegion = aRect;
1336                 rNativeContentRegion = aRect;
1337                 toReturn = sal_True;
1338             }
1339             break;
1340 
1341          case CTRL_TAB_ITEM:
1342 
1343             w = aCtrlBoundRect.GetWidth() + 2*TAB_TEXT_OFFSET - 2*VCL_TAB_TEXT_OFFSET;
1344 
1345 #ifdef OLD_TAB_STYLE
1346             h = TAB_HEIGHT_NORMAL;
1347 #else
1348             h = TAB_HEIGHT_NORMAL+2;
1349 #endif
1350             rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1351             rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1352 
1353             toReturn = sal_True;
1354 
1355             break;
1356 
1357         case CTRL_EDITBOX:
1358             {
1359                 w = aCtrlBoundRect.GetWidth();
1360                 if( w < 3+2*FOCUS_RING_WIDTH )
1361                     w = 3+2*FOCUS_RING_WIDTH;
1362                 h = TEXT_EDIT_HEIGHT_NORMAL+2*FOCUS_RING_WIDTH;
1363                 if( h < aCtrlBoundRect.GetHeight() )
1364                     h = aCtrlBoundRect.GetHeight();
1365 
1366                 rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*(FOCUS_RING_WIDTH+1), h-2*(FOCUS_RING_WIDTH+1) ) );
1367                 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1368 
1369                 toReturn = sal_True;
1370             }
1371             break;
1372         case CTRL_LISTBOX:
1373         case CTRL_COMBOBOX:
1374             {
1375                 if( nPart == PART_ENTIRE_CONTROL )
1376                 {
1377                     w = aCtrlBoundRect.GetWidth();
1378                     h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
1379 
1380                     rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*FOCUS_RING_WIDTH, h ) );
1381                     rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1382 
1383                     toReturn = sal_True;
1384                 }
1385                 else if( nPart == PART_BUTTON_DOWN )
1386                 {
1387                     w = aCtrlBoundRect.GetWidth();
1388                 if( w < 3+2*FOCUS_RING_WIDTH )
1389                     w = 3+2*FOCUS_RING_WIDTH;
1390                     h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
1391 
1392                     x += w-DROPDOWN_BUTTON_WIDTH - FOCUS_RING_WIDTH;
1393                     y += FOCUS_RING_WIDTH;
1394                     w = DROPDOWN_BUTTON_WIDTH;
1395 
1396                     rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1397                     rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
1398 
1399                     toReturn = true;
1400                 }
1401                 else if( nPart == PART_SUB_EDIT )
1402                 {
1403                     w = aCtrlBoundRect.GetWidth();
1404                     h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
1405 
1406                     x += FOCUS_RING_WIDTH;
1407                     x += 3; // add an offset for rounded borders
1408                     y += 2; // don't draw into upper border
1409                     y += FOCUS_RING_WIDTH;
1410                     w -= 3 + DROPDOWN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
1411                     if( nType == CTRL_LISTBOX )
1412                         w -= 9; // HIG specifies 9 units distance between dropdown button area and content
1413                     h -= 4; // don't draw into lower border
1414 
1415                     rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1416                     rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
1417 
1418                     toReturn = true;
1419                 }
1420             }
1421             break;
1422         case CTRL_SPINBOX:
1423                 if( nPart == PART_ENTIRE_CONTROL ) {
1424                     w = aCtrlBoundRect.GetWidth();
1425                     if( w < 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH )
1426                         w = 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH;
1427                     h = TEXT_EDIT_HEIGHT_NORMAL;
1428 
1429                     rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y ), Size( w-2*FOCUS_RING_WIDTH, h ) );
1430                     rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1431 
1432                     toReturn = sal_True;
1433                 }
1434                 else if( nPart == PART_SUB_EDIT ) {
1435                     w = aCtrlBoundRect.GetWidth() - SPIN_BUTTON_SPACE - SPIN_BUTTON_WIDTH;
1436                     h = TEXT_EDIT_HEIGHT_NORMAL;
1437                     x += 4; // add an offset for rounded borders
1438                     y += 2; // don't draw into upper border
1439                     w -= 8; // offset for left and right rounded border
1440                     h -= 4; // don't draw into upper or ower border
1441 
1442                     rNativeContentRegion = Rectangle( Point( x + FOCUS_RING_WIDTH, y + FOCUS_RING_WIDTH ), Size( w - 2* FOCUS_RING_WIDTH, h ) );
1443                     rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1444 
1445                     toReturn = sal_True;
1446                 }
1447                 else if( nPart == PART_BUTTON_UP ) {
1448                     //aCtrlBoundRect.GetWidth() contains the width of the full control
1449                     //ie the width of the textfield + button
1450                     //x is the position of the left corner of the full control
1451                     x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
1452                     y += FOCUS_RING_WIDTH - CLIP_FUZZ;
1453                     w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
1454                     h = SPIN_UPPER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
1455 
1456                     rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1457                     rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1458 
1459                     toReturn = sal_True;
1460                 }
1461                 else if( nPart == PART_BUTTON_DOWN ) {
1462                     x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
1463                     y += SPIN_UPPER_BUTTON_HEIGHT + FOCUS_RING_WIDTH - CLIP_FUZZ;
1464                     w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
1465                     h = SPIN_LOWER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
1466 
1467                     rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1468                     rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1469 
1470                     toReturn = sal_True;
1471                 }
1472             break;
1473         case CTRL_FRAME:
1474             {
1475                 sal_uInt16 nStyle = aValue.getNumericVal();
1476                 if(  ( nPart == PART_BORDER ) &&
1477                     !( nStyle & (FRAME_DRAW_MENU | FRAME_DRAW_WINDOWBORDER | FRAME_DRAW_BORDERWINDOWBORDER) ) )
1478                 {
1479                     Rectangle aRect(aCtrlBoundRect);
1480                     if( nStyle & FRAME_DRAW_DOUBLEIN )
1481                     {
1482                         aRect.Left()	+= 1;
1483                         aRect.Top() 	+= 1;
1484                         //rRect.Right()	-= 1;
1485                         //rRect.Bottom()	-= 1;
1486                     }
1487                     else
1488                     {
1489                         aRect.Left()	+= 1;
1490                         aRect.Top() 	+= 1;
1491                         aRect.Right()	-= 1;
1492                         aRect.Bottom()	-= 1;
1493                     }
1494 
1495                     rNativeContentRegion = aRect;
1496                     rNativeBoundingRegion = aRect;
1497 
1498                     toReturn = sal_True;
1499                 }
1500             }
1501             break;
1502 
1503         case CTRL_MENUBAR:
1504         case CTRL_MENU_POPUP:
1505             {
1506                 if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) {
1507 
1508                     w=10;
1509                     h=10;//dimensions of the mark (10px font)
1510 
1511                     rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1512                     rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1513 
1514                     toReturn = sal_True;
1515                 }
1516             }
1517             break;
1518 
1519     }
1520 
1521     return toReturn;
1522 }
1523