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