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